Delphi와 MSVC는 동일한 방식으로 + NAN을 0과 비교하지 않습니다.

Fpiette

C 코드를 Delphi로 이식 중이며 컴파일러 (Delphi 10.4.1 및 MSVC2019, 둘 다 x32 플랫폼을 대상으로 함)가 + NAN과 0의 비교를 처리하는 방식에 문제가 있습니다. 두 컴파일러 모두 이중 부동 소수점 값에 IEEE754 표현을 사용합니다. 델파이로의 C-Code I 이식이 코드 정확성을 검증하기 위해 많은 데이터와 함께 제공되기 때문에 문제를 발견했습니다.

원본 소스 코드는 복잡하지만 Delphi와 C 모두에서 최소한의 재현 가능한 애플리케이션을 생성 할 수있었습니다.

C- 코드 :

#include <stdio.h>
#include <math.h>

double AngRound(double x) {
    const double z = 1 / (double)(16);
    volatile double y;
    if (x == 0) 
        return 0;
    y = fabs(x);
    /* The compiler mustn't "simplify" z - (z - y) to y */
    if (y < z)
        y = z - (z - y);      // <= This line is *NOT* executed
    if (x < 0)
        return -y;
    else
        return y;             // <= This line is executed
}

union {
    double d;
    int bits[2];
} u;


int main()
{
    double lon12;
    double ar;
    int    lonsign;

    // Create a +NAN number IEEE754
    u.bits[0] = 0;
    u.bits[1] = 0x7ff80000;

    lon12    = u.d;                // Debugger shows lon12 is +nan
    if (lon12 >= 0)
        lonsign = 1;
    else
        lonsign = -1;              // <= This line is executed
    // Now lonsign is -1

    ar = AngRound(lon12);
    // Now ar is +nan

    lon12 = lonsign * ar;
    // Now lon12 is +nan
}

델파이 코드 :

program NotANumberTest;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type
    TRec = record
       case t : Boolean of
       TRUE:  (d    : Double);
       FALSE: (bits : array [0..1] of Cardinal);
    end;

function AngRound(x : Double) : Double;
const
    z : Double = 1 / Double(16);
var
    y : Double;
begin
    if x = 0 then
        Result := 0
    else begin
        y := abs(x);
        if y < z then
            // The compiler mustn't "simplify" z - (z - y) to y
            y := z - (z - y);           // <= This line is executed
        if x < 0 then
            Result := -y                // <= This line is executed
        else
            Result := y;
    end;
end;

var
    u       : TRec;
    lon12   : Double;
    lonsign : Integer;
    ar      : Double;
begin
    // Create a +NAN number IEEE754
    u.bits[0] := 0;
    u.bits[1] := $7ff80000;

    lon12 := u.d;                       // Debugger shows lon12 is +NAN
    if lon12 >= 0 then
        lonsign := 1                    // <= This line is executed
    else
        lonsign := -1;
    // Now lonsign is +1

    ar := AngRound(lon12);
    // Now ar is -NAN

    lon12 := lonsign * ar;
    // Now lon12 is -NAN
end.

비교 후 실행되는 줄을 표시했습니다. 델파이는 lon12 변수가 + NAN과 같을 때 (lon12> = 0)을 TRUE로 평가합니다. MSVC는 lon12 변수가 + NAN과 같을 때 (lon12> = 0)을 FALSE로 평가합니다.

lonsign은 C와 Delphi에서 다른 값을 가지고 있습니다.

+ NAN을 인수로받는 AngRound는 다른 값을 반환합니다.

lon12의 최종 값은 (치명적으로) 다릅니다.

컴파일러에 의해 생성 된 기계 코드는 다릅니다.

델파이가 생성 한 기계 코드 :

델파이 생성 기계 코드

MSVC2019 생성 기계 코드 :

MSVC2019 생성 기계 코드

비교 결과는 Delphi에서 더 논리적으로 보입니다. (lon12> = 0) lon12가 + NAN 일 때 TRUE입니다. 이것은 버그가 MSVC2019 컴파일러에 있음을 의미합니까? 원래 C-Code의 테스트 데이터 세트가 오류가있는 것으로 간주해야합니까?

데이비드 헤퍼 넌

우선, 당신의 델파이 프로그램은 적어도 제가 쉽게 사용할 수있는 델파이 버전 인 XE7에서는 당신이 설명하는대로 동작하지 않습니다. 프로그램이 실행되면 잘못된 연산 부동 소수점 예외가 발생합니다. 실제로 부동 소수점 예외를 마스크했다고 가정하겠습니다.

업데이트 : XE7과 10.3 사이에 Delphi 32 비트 코드 생성이 XE7이 IA 부동 소수점 예외를 설정하는 이유를 설명 fcom하는 fucom것으로 전환 되었지만 10.3은 그렇지 않은 것으로 나타났습니다.

Delphi 코드는 최소한의 수준과는 거리가 멀습니다. 진정으로 최소한의 예를 만들어 보겠습니다. 그리고 다른 비교 연산자를 살펴 보겠습니다.

{$APPTYPE CONSOLE}

uses
  System.Math;

var
  d: Double;
begin
  SetFPUExceptionMask(exAllArithmeticExceptions);
  SetSSEExceptionMask(exAllArithmeticExceptions);
  d := NaN;
  Writeln(d > 0);
  Writeln(d >= 0);
  Writeln(d < 0);
  Writeln(d <= 0);
  Writeln(d = d);
  Writeln(d <> d);
end.

XE7의 32 비트 미만에서이 출력은

진실
진실
그릇된
그릇된
진실
그릇된

10.3.3의 32 비트 (아래 주석에서보고 한대로 10.4.1)에서는 다음과 같이 출력됩니다.

진실
진실
진실
진실
그릇된
진실

XE7 및 10.3.3의 64 비트 (보고서는 10.4.1)에서 다음과 같이 출력됩니다.

그릇된
그릇된
그릇된
그릇된
그릇된
진실

64 비트 출력이 올 바릅니다. 두 변형 모두에 대한 32 비트 출력이 올바르지 않습니다. 이것은 IEEE754 NaN 값에 대해 false를 반환하는 모든 비교에 대한 근거는 무엇입니까? 를 참조하여 확인할 수 있습니다 .

연산자 ==, <=,> =, <,>를 사용한 모든 비교에서 하나 또는 두 값이 NaN 인 경우 다른 모든 값의 동작과는 반대로 false를 반환합니다.

32 비트 Delphi 코드의 경우이 버그를 해결하고 이러한 비교를 처리해야 할 때마다 특수한 경우 코드를 포함해야합니다. 물론, 당신이 10.4를 사용하고 있고 이미 문제가 해결되었다는 행복한 기회가 없다면.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

수동으로 변동성을 계산하는 것과 내장 함수를 비교하는 것은 동일하지 않습니다.

분류에서Dev

동일한 테이블에서 두 열을 비교하여 일치하지 않는 결과 만 얻는 방법

분류에서Dev

re.search () 및 re.match () 모두의 동일한 결과가 동일하지만 비교 연산자로 동일하지는 않습니다.

분류에서Dev

sas 매크로 문자열 비교는 같은 방식으로 동일하지 않습니다.

분류에서Dev

부동 소수점, 0으로 나누는 것을 방지하기에 충분한 동등 비교입니까?

분류에서Dev

PHP와 curl을 사용하여 Windows ping과 동일한 방식으로 ping을 수행하는 방법

분류에서Dev

polyfit의 최종 결과는 NaN이지만 행렬의 NaN을 삭제하고 동일한 크기를 남겼습니다. 도와주세요.

분류에서Dev

비교기가 0을 반환하는 동안 Java 8의 Collections.sort가 java 6으로 작동하지 않습니다.

분류에서Dev

부동 변수는 어떤 방식으로도 비교되지 않습니다.

분류에서Dev

()으로 PartialFunction을 적용하는 Scala는 .apply ()와 동일하지 않습니다.

분류에서Dev

키를 기반으로 두 해시 맵을 비교하는 방법과 값이 일치하지 않으면 불일치 키와 값을 인쇄해야합니다.

분류에서Dev

테이블의 모든 열을 동일한 '참조'열과 비교하여 참조와 다른 열이 있는지 확인합니다.

분류에서Dev

테이블의 모든 열을 동일한 '참조'열과 비교하여 참조와 다른 열이 있는지 확인합니다.

분류에서Dev

@JsonIdentityReference는 동일한 값을 인식하지 않습니다.

분류에서Dev

통화 값을 부동 소수점으로 비교하는 것이 작동하지 않습니다.

분류에서Dev

이전 값과 새 값을 각도 시계와 비교하여 동일한 지 확인하는 이유

분류에서Dev

자체 속기는 클래스 << 자체 레일과 같은 방식으로 작동하지 않습니다.

분류에서Dev

파이썬에서 대소 문자를 구분하지 않는 방식으로 변수 이름과 파일 이름을 비교하는 방법이 있습니까?

분류에서Dev

두 문자열을 비교하는 방법? 여기에 내 코드가 있으며 원하는 결과를 제공하지 않습니다. 제대로 비교되지 않습니다

분류에서Dev

Cassandra는 DecimalType 비교기로 작동하지 않습니다.

분류에서Dev

if 문에서 하나의 값을 'NaN'과 비교하는 방법 : Python 3.5.2 | Anaconda 4.1.0 (64 비트) 예 : a! = Nan 여기서 a는 부동 소수점 값입니다.

분류에서Dev

Marble 테스트의 각도 NgRx 효과 오류 : $ .length = 0이 2와 같을 것으로 예상됩니다. / $ [0] = 동일한 개체가 정의되지 않았습니다.

분류에서Dev

컨테이너와 이니셜 라이저 목록을 비교하여 동일한 지 확인하는 방법은 무엇입니까?

분류에서Dev

날짜 비교 : 날짜와 시간을 기준으로 페이지로 리디렉션합니다. 이것은 작동하지 않습니다

분류에서Dev

strcmp는 '동일한'문자열에서 0을 반환하지 않습니다.

분류에서Dev

numpy의 FFT와 MATLAB의 FFT는 동일한 결과를 갖지 않습니다.

분류에서Dev

나는 행렬이 대칭인지 아닌지를 확인하는 프로그램을 코딩했습니다. 둘 다 정확 해 보이지만 한 가지 방식으로 작동하지만 다른 방식으로는 작동하지 않습니다.

분류에서Dev

sympy 모듈로는 비 교환 식에서 작동하지 않습니다.

분류에서Dev

다른 파일에서 파일을 grep하는 것은 한 가지 방식으로 만 작동합니다. 왜?

Related 관련 기사

  1. 1

    수동으로 변동성을 계산하는 것과 내장 함수를 비교하는 것은 동일하지 않습니다.

  2. 2

    동일한 테이블에서 두 열을 비교하여 일치하지 않는 결과 만 얻는 방법

  3. 3

    re.search () 및 re.match () 모두의 동일한 결과가 동일하지만 비교 연산자로 동일하지는 않습니다.

  4. 4

    sas 매크로 문자열 비교는 같은 방식으로 동일하지 않습니다.

  5. 5

    부동 소수점, 0으로 나누는 것을 방지하기에 충분한 동등 비교입니까?

  6. 6

    PHP와 curl을 사용하여 Windows ping과 동일한 방식으로 ping을 수행하는 방법

  7. 7

    polyfit의 최종 결과는 NaN이지만 행렬의 NaN을 삭제하고 동일한 크기를 남겼습니다. 도와주세요.

  8. 8

    비교기가 0을 반환하는 동안 Java 8의 Collections.sort가 java 6으로 작동하지 않습니다.

  9. 9

    부동 변수는 어떤 방식으로도 비교되지 않습니다.

  10. 10

    ()으로 PartialFunction을 적용하는 Scala는 .apply ()와 동일하지 않습니다.

  11. 11

    키를 기반으로 두 해시 맵을 비교하는 방법과 값이 일치하지 않으면 불일치 키와 값을 인쇄해야합니다.

  12. 12

    테이블의 모든 열을 동일한 '참조'열과 비교하여 참조와 다른 열이 있는지 확인합니다.

  13. 13

    테이블의 모든 열을 동일한 '참조'열과 비교하여 참조와 다른 열이 있는지 확인합니다.

  14. 14

    @JsonIdentityReference는 동일한 값을 인식하지 않습니다.

  15. 15

    통화 값을 부동 소수점으로 비교하는 것이 작동하지 않습니다.

  16. 16

    이전 값과 새 값을 각도 시계와 비교하여 동일한 지 확인하는 이유

  17. 17

    자체 속기는 클래스 << 자체 레일과 같은 방식으로 작동하지 않습니다.

  18. 18

    파이썬에서 대소 문자를 구분하지 않는 방식으로 변수 이름과 파일 이름을 비교하는 방법이 있습니까?

  19. 19

    두 문자열을 비교하는 방법? 여기에 내 코드가 있으며 원하는 결과를 제공하지 않습니다. 제대로 비교되지 않습니다

  20. 20

    Cassandra는 DecimalType 비교기로 작동하지 않습니다.

  21. 21

    if 문에서 하나의 값을 'NaN'과 비교하는 방법 : Python 3.5.2 | Anaconda 4.1.0 (64 비트) 예 : a! = Nan 여기서 a는 부동 소수점 값입니다.

  22. 22

    Marble 테스트의 각도 NgRx 효과 오류 : $ .length = 0이 2와 같을 것으로 예상됩니다. / $ [0] = 동일한 개체가 정의되지 않았습니다.

  23. 23

    컨테이너와 이니셜 라이저 목록을 비교하여 동일한 지 확인하는 방법은 무엇입니까?

  24. 24

    날짜 비교 : 날짜와 시간을 기준으로 페이지로 리디렉션합니다. 이것은 작동하지 않습니다

  25. 25

    strcmp는 '동일한'문자열에서 0을 반환하지 않습니다.

  26. 26

    numpy의 FFT와 MATLAB의 FFT는 동일한 결과를 갖지 않습니다.

  27. 27

    나는 행렬이 대칭인지 아닌지를 확인하는 프로그램을 코딩했습니다. 둘 다 정확 해 보이지만 한 가지 방식으로 작동하지만 다른 방식으로는 작동하지 않습니다.

  28. 28

    sympy 모듈로는 비 교환 식에서 작동하지 않습니다.

  29. 29

    다른 파일에서 파일을 grep하는 것은 한 가지 방식으로 만 작동합니다. 왜?

뜨겁다태그

보관