문제

Math.floor()를 사용하는 대신 숫자를 .5만큼 오른쪽으로 이동할 수 있다고 들었습니다.적절한 대체품인지 확인하기 위해 제한 사항을 확인하기로 결정하고 다음 값을 확인한 결과 Google Chrome에서 다음과 같은 결과를 얻었습니다.


2.5 >> .5 == 2;
2.9999 >> .5 == 2;
2.999999999999999 >> .5 == 2;  // 15 9s
2.9999999999999999 >> .5 == 3;  // 16 9s

약간의 조정 끝에 Chrome과 Firefox에서 오른쪽으로 0.5만큼 시프트하면 2가 나올 수 있는 가장 높은 값은 2.9999999999999997779553950749686919152736663818359374999999̅(9가 반복됨)이라는 사실을 알아냈습니다.IE에서는 숫자가 2.9999999999999997779̅ 입니다.

내 질문은 다음과 같습니다숫자 .0000000000000007779553950749686919152736663818359374의 의미는 무엇입니까?그것은 매우 이상한 숫자이고 정말 나의 호기심을 자극했습니다.

나는 답이나 적어도 어떤 종류의 패턴을 찾으려고 노력해 왔지만 내 문제는 비트 연산을 실제로 이해하지 못한다는 사실에 있다고 생각합니다.원칙적으로는 아이디어를 이해하지만 비트 시퀀스를 .5만큼 이동하는 것은 나에게 전혀 의미가 없습니다.도움을 주시면 감사하겠습니다.

기록상 이상한 숫자 순서는 2^x로 변경됩니다.여전히 적절하게 잘리는 다음 숫자의 가능한 가장 높은 값:

for 0: 0.9999999999999999444888487687421729788184165954589843749¯
for 1: 1.9999999999999999888977697537484345957636833190917968749¯
for 2-3: x+.99999999999999977795539507496869191527366638183593749¯
for 4-7: x+.9999999999999995559107901499373838305473327636718749¯
for 8-15: x+.999999999999999111821580299874767661094665527343749¯
...and so forth
도움이 되었습니까?

해결책

실제로는 부동 소수점 연산이 진행되지 않고 첫 번째 피연산자에서 Floor()를 수행하게 됩니다.왼쪽 시프트 및 오른쪽 시프트 비트 단위 연산은 정수 피연산자에서만 의미가 있으므로 JavaScript 엔진은 먼저 두 피연산자를 정수로 변환합니다.

2.999999 >> 0.5

다음과 같이 됩니다:

Math.floor(2.999999) >> Math.floor(0.5)

이는 다음과 같습니다.

2 >> 0

0비트로 이동한다는 것은 "교대를 수행하지 않음"을 의미하므로 단순히 정수로 잘린 첫 번째 피연산자로 끝납니다.

SpiderMonkey 소스 코드는 다음과 같습니다:

switch (op) {
  case JSOP_LSH:
  case JSOP_RSH:
    if (!js_DoubleToECMAInt32(cx, d, &i)) // Same as Math.floor()
        return JS_FALSE;
    if (!js_DoubleToECMAInt32(cx, d2, &j)) // Same as Math.floor()
        return JS_FALSE;
    j &= 31;
    d = (op == JSOP_LSH) ? i << j : i >> j;
    break;

특정 숫자에서 "반올림"이 표시되는 것은 JavaScript 엔진이 특정 정밀도를 초과하는 소수점 자리를 처리할 수 없기 때문에 숫자가 다음 정수로 반올림되기 때문입니다.브라우저에서 다음을 시도해 보세요.

alert(2.999999999999999);

2.999999999999999를 얻게 됩니다.이제 9를 하나 더 추가해 보세요.

alert(2.9999999999999999);

당신은 3을 얻을 것이다.

다른 팁

이것은 아마도 내가 본 최악의 아이디어 일 것입니다. 기존의 유일한 목적은 난처한 코드 콘테스트에서 우승하는 것입니다. 당신이 게시 한 긴 숫자에는 의미가 없습니다. 그들은 기본 부동 소수점 구현의 인공물이며, 얼마나 많은 중간 계층 수를 통해 필터링되었습니다. 부분적으로 바이트로 비트가 이동하는 것은 미쳤으며 예외가 제기되지 않는다는 것에 놀랐습니다. 그러나 그것은 JavaScript이며 항상 "미치광이"를 재정의하려고합니다.

내가 당신이라면, 나는이 "기능"을 사용하지 않을 것입니다. 유일한 값은 비정상적인 오류 조건의 가능한 근본 원인입니다. 사용 Math.floor() 코드를 유지할 다음 프로그래머에게 동정심을 느낍니다.


질문을 읽을 때 내가 가진 몇 가지 의심을 확인합니다.

  • 분수 번호를 우회전합니다 x 모든 분수 번호로 y 단순히 잘립니다 x, 동일한 결과를 제공합니다 Math.floor() 독자를 완전히 혼란스럽게하는 동안.
  • 2.99999999999999777955395074968691915 ...은 단순히 "3"과 차별화 될 수있는 가장 큰 숫자입니다. 자체적으로 평가해보십시오. 추가하면 3으로 평가됩니다. 이는 브라우저와 로컬 시스템의 부동 소수점 구현의 아티팩트입니다.

더 깊이 가고 싶다면 "모든 컴퓨터 과학자가 부동 소수점 산술에 대해 알아야 할 사항"을 읽으십시오. http://docs.sun.com/source/806-3568/ncg_goldberg.html

나는 당신의 올바른 변화가 관련이 있다고 생각하지 않습니다. 당신은 단순히 이중 정밀 부동 소수점 상수의 해상도를 넘어선 것입니다.

크롬에서 :

var x = 2.999999999999999777955395074968691915273666381835937499999;
var y = 2.9999999999999997779553950749686919152736663818359375;

document.write("x=" + x);
document.write(" y=" + y);

인쇄물 : x = 2.999999999999996 y = 3

이 JavaScript를 시도해보십시오 : Alert (parsefloat ( "2.99999999999997797979539507494968691915273666381835937499999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 명 경고 경문 ') ;속 조입니다);

Alert ( "2.9999999999779795395074968691915273663818359375");

당신이보고있는 것은 단순한 부동 소수점 부정확입니다. 이에 대한 자세한 내용은 예를 들어 다음을 참조하십시오. http://en.wikipedia.org/wiki/floating_point#accuracy_problems.

기본 문제는 부동 소수점 값이 두 번째 숫자를 나타낼 수있는 가장 가까운 것이 3보다 크거나 동일하지만 A Float가 첫 번째 숫자로 얻을 수있는 마감은 엄격히 3보다 작습니다.

오른쪽으로 0.5로 이동하는 이유는 전혀 제정신이 제정신으로, 0.5 자체가 int (0)로 변환되는 것으로 보입니다. 그런 다음 원래 플로트 (2.999 ...)가 평소와 같이 잘린 int로 변환됩니다.

시프트 오른쪽 연산자는 정수 (양쪽)에서만 작동합니다. 따라서 .5 비트로 바로 이동하는 것은 0 비트로 바로 이동하는 것과 정확히 동일해야합니다. 그리고 왼쪽은 시프트 작동 전에 정수로 변환되며, 이는 Math.floor ()와 동일한 작업을 수행합니다.

2.999999999999999999999999999999999999915273666363818359374999999로 바이너리 표현으로 깨달을 것이라고 생각합니다. 아마도 True 3과 1 비트 만 다릅니다.

좋은 추측이지만 시가는 없습니다. Double Precision FP 번호는 53 비트를 가지므로 3 이전의 마지막 FP 수는 실제로 (정확한) : 2.9999999999999995559107901499383830547332763671875

그러나 왜 2.999999999999999997777795395074968691915273663818359375인가

(그리고 이것은 49999가 아니라 정확합니다 ...!)

그게 더 높은 마지막 표시 가능한 장치보다? 반올림. 변환 루틴 (문자열에서 숫자)은 다음 플로팅 포인트 번호를 입력을 반올림하도록 올바르게 프로그래밍됩니다.

2.999999999999999555910790149937383830547332763671875

....... (값 사이의 값, 증가) -> 라운드 다운

2.9999999999999997779553950749686919152736663818359375

....... (값 사이의 값, 증가) -> 라운드 업 최대 3

3

변환 입력은 완전 정밀도를 사용해야합니다. 숫자가 정확히 2 개의 FP 숫자 (2.999999999999977979795395074949686919152736663818359375 사이의 절반 인 경우 반올림은 설정된 플래그에 따라 다릅니다. 기본 반올림은 짝수로 짝을 이루어 숫자가 다음 짝수로 반올림됩니다.

지금

3 = 11. (이진)

2.999 ... = 10.11111111111 ...... (Binary)

모든 비트가 설정되고 숫자는 항상 홀수입니다. 즉, 정확한 절반 숫자가 반올림되므로 이상한 일을 받고 있습니다.

2.999999999999999999999999999999999991527366663638183593749999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 미 할까지 깨달을 것으로 의심됩니다. 아마도 True 3과 1 비트 만 다릅니다.

그리고 요한의 대답에 추가하기 위해,이 확률은 수학보다 더 성능이 좋을 것입니다.

JavaScript가 부동 소수점 번호 또는 일종의 무한-프레임 라이브러리를 사용하는지 모르겠지만, 어느 쪽이든, 당신은 이와 같은 작업에서 반올림 오류를 얻을 것입니다.

숫자 ".000000000000000007777779553950749691919152736663818359374"라는 점에 유의해야합니다. 엡실론, "(1+e)> 1과 같이"가장 작은 숫자 e "로 정의됩니다.

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