2017-02-21 4 views
-2

나는 통해 보았다 : Why can't decimal numbers be represented exactly in binary?Why Are Floating Point Numbers Inaccurate?루비 반올림하고 소수의 형식

내가 라운드와 루비를 사용하여 부동 소수점 숫자 형식, 결과는 여전히 수학을 수행 한 결과 다른 때 나의 질문은

손을 구매 . 다음은이의 예입니다

편집 2

[28] pry(main)> ##################################### 
[29] pry(main)> # test one 
[30] pry(main)> ##################################### 
[31] pry(main)> foo = (6.0135 * (650000/1000)) 
      => 3908.7749999999996 
[32] pry(main)> foo = '%.2f' % foo.round(2) 
      => "3908.77" 
[33] pry(main)> # should be 3908.78 

[36] pry(main)> ##################################### 
[37] pry(main)> # test two 
[38] pry(main)> ##################################### 
[39] pry(main)> foo = 650000/1000 
      => 650 
[40] pry(main)> foo = foo * 6.0135 
      => 3908.7749999999996 
[41] pry(main)> foo = '%.2f' % foo.round(2) # should be 3908.78 
      => "3908.77" 

[44] pry(main)> ##################################### 
[45] pry(main)> # test three 
[46] pry(main)> ##################################### 
[47] pry(main)> foo = 650000/1000 
      => 650 
[48] pry(main)> foo = foo * 6.0135 
      => 3908.7749999999996 
[49] pry(main)> foo = foo.round(2) # should be 3908.78 
=> 3908.77 

[52] pry(main)> ##################################### 
[53] pry(main)> # test four - The result of test four is expected 
[54] pry(main)> ##################################### 
[55] pry(main)> foo = 650000/1000 
      => 650 
[56] pry(main)> foo = foo * 6.0135 
      => 3908.7749999999996 
[57] pry(main)> foo = '%.2f' % foo 
      => "3908.77" 

[58] pry(main)> ##################################### 
[59] pry(main)> # test five 
[60] pry(main)> ##################################### 
[61] pry(main)> foo = 650000/1000 
      => 650 
[62] pry(main)> foo = foo * 6.0135 
      => 3908.7749999999996 
[63] pry(main)> foo = foo.round(5) 
      => 3908.775 

테스트 1 : 이것은 나에게 문제를주고 내 라이브러리에서 사용하는 일반적인 공식이다.

테스트 2 : '%.2f' %이 일을 자릅니다 일부 반올림 문제를 일으키는 것으로 알려져있다 글쎄, 어쩌면 이것은이다 : 여기에 내 생각은 어쩌면 몇 가지 문제

시험 (3)를 일으키는 하나 개의 할당에서 두 작업을하는 것이 었습니다 문제.

시험 4 : '%.2f' %이 문제가 아니기 때문에 .round(2)이 문제의 원인 일 수 있습니다.

편집 2 : 테스트 5 : 난 내가 (. 즉, 라운드 다시 (2) 그 숫자)와 함께 작동 할 수있는 번호를보고있다 ROUND 숫자를 확장합니다. 하지만 이것은 일반적인 경우가 아닌 제한된 경우에 효과가있는 불안정한 솔루션처럼 보입니다.

부동 소수점이 정확하지 않은 것에 대해서는별로 신경 쓰지 않습니다. 제 질문은이 번호를 올바르게 반올림하여 올바른 답을 얻을 수 있도록하는 것입니다 (수동으로 작업을 수행 한 경우 얻을 수있는 대답).

또한 일반적으로 도징 포인트 오류를 ​​수정하기위한 반올림에 대한 모범 사례가 있습니까? 부동 소수점 숫자를 나타 내기 위해서는 두 개의 정수를 사용하는 것이지만, 번거로 웠습니다.

감사합니다.

편집 한

당신이 .round(5) 대신 .round(2)의 사용하면 답이 있어야한다 무엇에 비교할 때 좀 더 합리적인 답변을 얻을 것입니다. 라운드 안의 숫자를 늘리는 데 단점이 있습니까?

+0

왜 downvote? –

+1

이 라운드는 정확합니다. 3908.77499999 .. 실제로 3908.775보다 작기 때문에 항상 3908.77이됩니다. 당신은 항상 전체 값을 반올림하고, 마지막 숫자를 중심으로 시작한 다음 앞으로 나아 가지 마십시오 .... –

+0

실제 답변은 3908.78이어야합니다. '.round (5)'를 사용하면 3908.78을 얻을 수 있습니다. –

답변

3

round 예상대로 작동합니다. 입력에 이미 결함이있어 잘못된 결과를 얻습니다. 부동 소수점 숫자 6.0135는 실제로 :

6.01349999999999962341235004714690148830413818359375 

650하여이 수를 곱하면 오류 악화시킨다.

foo = 6.0135 * 650 
#=> 3908.7749999999996 

(foo - 3908.77).abs 
#=> 0.004999999999654392 

(foo - 3908.78).abs 
#=> 0.005000000000563887 

올바른 결과를 얻으려면, 당신은 같은 것을 사용할 수 있습니다 :

foo = (6.0135 * 10000).round * 0.065 
#=> 3908.775 

foo.round(2) 
#=> 3908.78 

을 아니면 소수점 오류 부동 방지하기 위해 BigDecimal를 사용할 수 있습니다 당신은 3908.78보다 3908.77에 가까운 결과를 얻을 수 첫 번째 장소에서 :

require 'bigdecimal' 
foo = BigDecimal('6.0135') * 650 
foo.to_s('F') 
#=> "3908.775" 

foo.round(2).to_s('F') 
#=> "3908.78" 
+0

고맙습니다. 성능상의 타격을 제외하고 bigdecimal에 대한 큰 단점이 있습니까? 이 종류의 수학을 요청 당 25 번 수행하려고합니다.이 변경은 요청의 성능에 많은 영향을 미칩니 까? –

+1

@alex_milhouse 레일즈에서 요청 - 응답주기가 그렇게 가볍지 않습니다. 25 개의 계산이 눈에 띄게 영향을 주면 놀랄 것입니다. – Stefan

+0

great. 고마워, 이건 내가 필요한거야. –

0

'%.2f' %은 - 수를 절단하고 올바르게

.round(2) 라운드에 실패 - 제대로 반올림 다시 충분한 소수점을 보이지 않는다. 그래서 2보다 큰 숫자를 만들면 반올림 문제는 사라집니다.

편집 한

5 개 IEEE에 따라 숫자를 반올림하는 방법이 있습니다 : 가까운에

  1. , 넥타이에 가장 가까운 심지어
  2. , 넥타이 멀리 제로
  3. 에서 향해 0
  4. 향해 + ∞
  5. 향해 -∞

이 경우 나는 반올림 방법에 관한 것이 아니라 소수점 이하 자릿수를 고려해야합니다. 일반적으로 사람은 정밀도에 대해 걱정할 필요가 있습니다. 이 오류는 컴퓨터에 의해 만들어 지므로 고려해야 할 소수점 이하의 값을 늘리는 것이 더 정확하고 정확하다고 가정합니다.

+1

성격을 분할 했습니까? –

+1

저는 이것이 IEEE 부동 소수점 표준을 인용하여 이러한 진술을 정당화 할 필요가 있다고 생각합니다. –

+0

예 @muistooshort와 lukasz 나는 이것을 어떻게 "풀 었는지"에 대한 두 번째 생각을 실제로 가지고 있습니다. 이것은 내가이 특별한 경우에 대해 원했던 대답을 준다. 이 작업을 수행 할 때 다른 문제가 있습니까? –

0

내 레일 콘솔에 모든 것을 테스트하고 이상한 행동을 볼 수 없습니다 :

>> foo = 650000/1000 
=> 650 
>> foo = foo * 6.0135 
=> 3908.7749999999996 
>> foo.round(2) 
=> 3908.77 
>> foo.round(3) 
=> 3908.775 
>> foo.round(5) 
=> 3908.775 
>> afoo = '%.2f' % foo 
=> "3908.77" 
>> afoo = '%.5f' % foo 
=> "3908.77500" 

3908.7749999999996는 3908.775보다 작은 당신이 .round (2) 사용하는 경우 3908.77로 내림됩니다. . (5) 결과는 3908.775에서 예상대로 나타나며 Google 계산기로도 재생할 수 있습니다. 왜 이것이 틀렸어 야한다고 생각하니? 나는 그것을 이해하고 정말로 싶습니다.