문제

Java와 C/C ++에서 여러 참조 알고리즘을 코딩하고 있습니다. 이 알고리즘 중 일부는 π를 사용합니다. 각 알고리즘의 두 가지 구현을 생성하고 싶습니다. 동일한 다르게 반올림하지 않고 결과. 지금까지 일관되게 작동 한 한 가지 방법은 사용자 정의 정의를 사용하는 것입니다. pi 3.14159와 같은 두 언어에서 정확히 동일한 상수. 그러나 Java 및 GCC 라이브러리에 이미 정의 된 고정밀 상수가있을 때 PI를 정의하는 것은 어리석은 일입니다.

나는 빠른 테스트 프로그램을 작성하고 각 라이브러리에 대한 문서를보고, 부동 소수점 유형을 읽는 데 시간을 보냈습니다. 그러나 나는 java.lang.math.pi (또는 java.lang.strictmath.pi)가 Math.h의 m_pi와 같지 않다고 스스로를 확신시킬 수 없었습니다.

GCC 3.4.4 (Cygwin) Math.h 포함 :

#define M_PI            3.14159265358979323846
                                         ^^^^^

하지만 이것은

printf("%.20f", M_PI);

생산합니다

3.14159265358979311600
                 ^^^^^

마지막 5 자리는 신뢰할 수 없음을 시사합니다.

한편 Javadocs는 java.lang.math.pi라고 말합니다.

그만큼 double 다른 것보다 더 가까운 가치 pi, 원의 둘레 대 직경의 비율.

그리고

public static final double PI  3.141592653589793d

상수에서 의심스러운 마지막 5 자리를 생략합니다.

System.out.printf("%.20f\n", Math.PI);

생산합니다

3.14159265358979300000
                 ^^^^^

플로팅 포인트 데이터 유형에 대한 전문 지식이 있다면 이러한 라이브러리 상수가 정확히 동일하다는 것을 확신시켜 줄 수 있습니까? 아니면 분명히 같지 않습니까?

도움이 되었습니까?

해결책 4

예, 그것들은 동일하며, 그것들을 사용하면 동일한 알고리즘의 GCC 및 Java 구현이 동일한 기반에 있습니다. 적어도 손으로 정의 된 것을 사용하는 것만 큼 pi 일정 할 것입니다.

한 번의 경고가 암시되었습니다 S. 로트, GCC 구현은 보유해야한다는 것입니다 M_PI 안에 double 데이터 유형이 아닙니다 long double, 동등성을 보장하기 위해. Java와 GCC는 모두 각각의 IEEE-754의 64 비트 소수점 표현을 사용하는 것으로 보입니다. double 데이터 유형. 라이브러리 값의 바이트 워시 표현 (MSB에서 LSB). double, 다음과 같이 얻을 수 있습니다 (감사합니다 Jeebee):

pi_bytes.c :

#include <math.h>
#include <stdio.h>
int main()
{
   double pi = M_PI;
   printf("%016llx\n", *((uint64_t*)&pi));
}

pi_bytes.java :

class pi_bytes
{
   public static void main(String[] a)
   {
      System.out.printf("%016x\n", Double.doubleToRawLongBits( Math.PI ) );
   }
}

둘 다 실행 :

$ gcc -lm -o pi_bytes pi_bytes.c && ./pi_bytes
400921fb54442d18

$ javac pi_bytes.java && java pi_bytes
400921fb54442d18

의 기본 표현 M_PI (A로 double) 그리고 Math.PI 비트와 동일합니다.

† - 언급 한 바와 같이 Steve Schnepp, Sin, Cos, Exp 등과 같은 수학 기능의 출력은 해당 계산에 대한 입력이 약간 동일하더라도 동일하게 보장되지 않습니다.

다른 팁

다음을 참고하십시오.

두 숫자는 소수점 이하 16 자리와 동일합니다. 거의 48 비트입니다.

IEEE 64 비트 부동산 지점에서는 징후 나 지수가 아닌 모든 비트입니다.

그만큼 #define M_PI 21 자리가 있습니다. 그것은 약 63 비트의 정밀도이며, IEEE 80 비트 플로팅 포인트 값에 좋습니다.

내가 당신이보고있는 것은 M_PI 값.

당신이하고 싶은 것은 PI 값의 원시 비트 패턴을 인쇄하고 비교하는 것입니다.

Java에서 http://java.sun.com/j2se/1.5.0/docs/api/java/lang/double.html#doubletorawlongbits(double) 방법 이진으로 인쇄 해야하는 긴 값을 얻는 방법.

Java 5는 다음과 같습니다.

  • PI는 3.141592653589793입니다
  • 원시 비트는 4614256655552045848입니다
  • 바이너리는 10000000000010010010011111110110101010001000010110100011000입니다

C에서는 할 수 있습니다 double pi = M_PI; printf("%lld\n", pi); 동일한 64 비트 정수를 얻으려면 : 46142566565552045848 (감사합니다 Bruno).

동일한 값을 계산하는 것은 매우 어려울 것입니다. 시작 값이 동일하더라도.

플로팅 포인트 계산 결과는 아키텍처와 다른 제품 (예 : X86/PowerPC 생각), 컴파일러에서 다른 컴파일러 (GCC/MS C ++ 생각) 및 동일한 컴파일러를 사용하지만 컴파일 옵션에 따라 다릅니다. 항상 그런 것은 아니지만 때로는 (보통 둥글 때). 일반적으로 문제가 너무 늦을 때까지 문제가 눈에 띄지 않을 정도로 충분합니다 (많은 반복을 후에 생각하고 많은 반올림 차이를 생각해보십시오)

따라서 게임의 각 반복을 동기식으로 계산하는 크로스 플랫폼 멀티 플레이어 게임은 상당히 어렵습니다 (각 노드는 실제 데이터 구조가 아니라 입력 만 수신합니다).

따라서 동일한 언어 (C/C ++) 결과에서도 Java VM에서 기본 호스트에 이르기까지 다를 수 있습니다.

업데이트:

내가 읽은 소스를 찾을 수 없지만 태양에 의한 종이 이 문제에.

당신이 스스로 대답했던 것처럼 java.lang.math.pi 및 gcc의 m_pi는 동일한 값을 가질 수 있습니다.. 악마는이 가치를 사용하여 숨 깁니다. IEEE는 수학 기능의 출력을 지정하지 않습니다 (sin, cos, exp, ...). 그러므로 그것은입니다 계산의 출력 반드시 같은 것은 아닙니다.

더블은 52 비트의 Signficand와 비슷합니다. 그래서 나는 당신에게 20 자리를 요구할 때 5 개의 0을 가지고있는 이유를 설명 할 수있는 15 개의 기본 10 자리 만 제공한다고 생각합니다.

다음과 같은 정확도를 위해 BigDecimal을 사용할 수 있습니다.

private static final BigDecimal PI = new BigDecimal(
"3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679" +
    "8214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196" +
    "4428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273" +
    "7245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094" +
    "3305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912" +
    "9833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132" +
    "0005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235" +
    "4201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859" +
    "5024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303" +
    "5982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989" +
    "3809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151" +
    "5574857242454150695950829533116861727855889075098381754637464939319255060400927701671139009848824012" +
    "8583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912" +
    "9331367702898915210475216205696602405803815019351125338243003558764024749647326391419927260426992279" +
    "6782354781636009341721641219924586315030286182974555706749838505494588586926995690927210797509302955" +
    "3211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000" +
    "8164706001614524919217321721477235014144197356854816136115735255213347574184946843852332390739414333" +
    "4547762416862518983569485562099219222184272550254256887671790494601653466804988627232791786085784383" +
    "8279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863" +
    "0674427862203919494504712371378696095636437191728746776465757396241389086583264599581339047802759009" +
    "9465764078951269468398352595709825822620522489407726719478268482601476990902640136394437455305068203" +
    "4962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382" +
    "6868386894277415599185592524595395943104997252468084598727364469584865383673622262609912460805124388" +
    "4390451244136549762780797715691435997700129616089441694868555848406353422072225828488648158456028506" +
    "0168427394522674676788952521385225499546667278239864565961163548862305774564980355936345681743241125"
);

public static void main(String... args) throws InterruptedException {
    System.out.println("PI to " + PI.scale() + " digits is " + PI);
    System.out.println("PI^2 to " + PI.scale() + " digits is " + 
            PI.multiply(PI).setScale(PI.scale(), BigDecimal.ROUND_HALF_UP));
}

Fortran에서 PI의 가치를 얻어야한다는 기억을 되 찾습니다.

상수 라이브러리가 없었기 때문에 4*atan (1.) 또는 ACOS (-1)을 사용했습니다.

아니요, 동일하지 않으며 메모리에 다른 프레젠테이션이 있습니다.

일반적으로 2 개의 플로팅 포인트 값을 비교하려면 ==를 사용해서는 안됩니다 (그렇다면 'Equals'에서 작동 할 수 없습니다). Epsilon과 비교해야합니다.

double eps = 0.0000001;
if (Math.abs (Java_PI - Another_Pi) <= eps)
  System.out.println ("equals");
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top