문제

정밀 손실을 최소화하기 위해 플로팅 포인트 계산으로 약간의 테스트를 수행했습니다. 나는 여기에 보여주고 싶은 현상을 우연히 발견하고 희망적으로 설명을 얻었습니다.

내가 쓸 때

print 1.0 / (1.0 / 60.0)

결과는입니다

60.0024000960

내가 같은 공식을 작성하고 명시 적 캐스팅을 할 때 float

print cast(1.0 as float) / (cast(1.0 as float) / cast(60.0 as float))

결과는입니다

60

지금까지 나는 소수점 이하 자리가있는 숫자 리터럴이 자동으로 처리된다고 생각했습니다. float 적절한 정밀도로 값. 캐스팅 real 캐스팅과 동일한 결과를 보여줍니다 float.

  • SQL Server가 숫자 리터럴을 평가하는 방법에 대한 문서가 있습니까?
  • 그 리터럴은 어떤 데이터 유형입니까?
  • 나는 정말로 그들을 캐스팅해야합니까? float 더 나은 정밀도를 얻으십시오 (나에게 아이러니처럼 들립니다 :)?
  • 내 공식을 캐스트로 혼란시키는 것보다 쉬운 방법이 있습니까?
도움이 되었습니까?

해결책

SQL Server는 가능한 가장 작은 데이터 유형을 사용합니다.

이 스크립트를 실행할 때

SELECT SQL_VARIANT_PROPERTY(1.0, 'BaseType')
SELECT SQL_VARIANT_PROPERTY(1.0, 'Precision')
SELECT SQL_VARIANT_PROPERTY(1.0, 'Scale')
SELECT SQL_VARIANT_PROPERTY(1.0, 'TotalBytes')

SQL Server는 숫자 (2, 1) 데이터 유형을 암시 적으로 사용했음을 알 수 있습니다.
60.0의 부서는 결과를 숫자로 변환합니다 (8, 6).
최종 계산은 결과를 숫자로 변환합니다 (17, 10).


편집하다

SQL Server Books에서 온라인으로 가져온 것입니다 데이터 유형 변환

Transact-SQL 문서에서, 소수점이있는 상수는 필요한 최소 정밀도와 스케일을 사용하여 숫자 데이터 값으로 자동 변환됩니다. 예를 들어, 상수 12.345는 정밀도가 5이고 스케일 3의 숫자 값으로 변환됩니다.

다른 팁

그렇습니다. 더 나은 정밀도를 얻으려면 자주 캐스트해야합니다. 내 테이크 :

계산하기 전에 더 나은 정밀 캐스트 소수를 위해

비슷한 경우에 향후 참조를 위해 무대 뒤에서 무슨 일이 일어나고 있는지 이해해야한다고 생각합니다.

과학적 표기법을 제외한 소수점 지점을 가진 리터럴 숫자 값은 최소 소수점 유형으로 저장되는 10 진수 데이터 유형을 나타냅니다. Lieven Keersmaekers 's와 동일한 인용문 :https://msdn.microsoft.com/en-us/library/ms191530%28sql.90%29.aspx#_decimal

Transact-SQL 문서에서, 소수점이있는 상수는 필요한 최소 정밀도와 스케일을 사용하여 숫자 데이터 값으로 자동 변환됩니다. 예를 들어, 상수 12.345는 정밀도가 5이고 스케일 3의 숫자 값으로 변환됩니다.

소수점의 오른쪽에있는 후행 0은 척도를 지정합니다. 소수점에서 남은 주요 0은 무시됩니다.

몇 가지 예 :

1.0  -> Decimal(2,1)
60.0 -> Decimal(3,1)
1.00 -> Decimal(3,2)
01.0 -> Decimal (2,1)

고려해야 할 또 다른 요점입니다 데이터 유형 우선 순위. 연산자가 서로 다른 데이터 유형의 두 가지 표현을 결합한 경우, 데이터 유형 우선 순위에 대한 규칙은 우선 순위가 낮은 데이터 유형이 더 높은 우선 순위로 데이터 유형으로 변환되도록 지정합니다. 그리고 고려해야 할 또 다른 요점은 우리가 소수점 유형에 대해 산술 연산을 수행하는 경우, 그 결과 소수점 유형, 즉 정밀도 및 스케일이 피연산자와 작동 자체에 따라 다르다는 것입니다. 이것은 문서에 설명되어 있습니다 정밀, 규모 및 길이.

따라서 괄호 안에있는 표현의 일부

( 1.0 / 60.0 ) is evaluated to 0.016666 and the resulting type is Decimal (8,6)

소수점 표현의 정밀 및 규모에 대한 위의 규칙을 사용합니다. 또한 은행가의 반올림 또는 반올림도 사용됩니다. 소수점 및 플로트 유형에 대해 다른 반올림을 주목하는 것이 중요합니다. 우리가 표현을 계속한다면

1.0 / 0.016666 is evaluated to 60.002400096 and the resulting type is Decimal (17,10)

따라서 불일치의 일부는 플로트와는 10 진수 유형에 대해 다른 반올림으로 인한 것입니다.

위 규칙에 따라 괄호 안에 하나의 캐스트 만 사용하는 것으로 충분합니다. 다른 모든 리터럴은 데이터 유형 우선 순위 규칙에 따라 플로트로 홍보됩니다.

1.0 / (1.0 / cast(60.0 as float))

그리고 한 가지 더 중요한 것. 이 플로트 표현조차도 정확한 결과를 계산하지 않습니다. 그것은 단지 프론트 엔드 (SSMS 또는 무엇이든)가 값을 정밀한 6 자리 (정밀한)로 반올림 한 다음 후행 0을 잘라냅니다. 따라서 IE 1.000001은 1이됩니다.

단순하지 않습니까?

일정한 플로트 표현식을 작성하려면 과학 표기법을 사용하십시오.

select (1.0E0 / (1.0E0 / 60.0E0))

결과는 60입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top