double 소수점 계산 관련 문의
-
안녕하세요.
qt 5.12.x 버전 사용중에 있고 소수점 계산 중에 궁금한 부분이 있어 문의드립니다.
double a = 0.00025;
double sum = 0.0;for(int i = 0; i < 100000; i++)
{
sum += a;
}이렇게 계산을 할 경우 0.00025씩 증가하여야 하는데 값을 출력해보면 0.827998 이런식으로 깨져서 표시됩니다.
아래와 같이 ceil이나 round 함수를 사용해도 0.00025씩 동일하게 증가하여 표시되게 하는 좋은 방법이 없을까요?
ceil(a * 1000000) / 1000000;
round(a * 1000000) / 1000000;ps) window 10, ubuntu 20.04 버전 동일합니다.
-
Hi @hlowd, what you are seeing here an accumulative floating point error that comes from the fact that floating point numbers cannot represent every possible number exactly.
The solution is to use a fixed-point approach instead of floating - ie using integers, but where the integers represent a decimal fraction instead of whole units.
Easier explained with an example:
This doesn't work, as you've shown already:
#include <iostream> int main() { double a = 0.00025; double sum = 0.0; for(int i = 0; i < 100000; i++) { sum += a; std::cout << sum << std::endl; } }
Outputs:
0.00025 0.0005 0.00075 0.001 0.00125 ... 24.999 24.9993 24.9995 24.9998 25
But this version:
#include <iomanip> #include <iostream> int main() { uint64_t a = 25; uint64_t sum = 0; for(int i = 0; i < 100000; i++) { sum += a; std::cout << (sum/100000) << '.' << std::setfill('0') << std::setw(5) << (sum%10000) << std::endl; } }
Outputs what you want (if I understand you correctly):
0.00025 0.00050 0.00075 0.00100 0.00125 ... 24.09900 24.09925 24.09950 24.09975 25.00000
Of course, the
std::*
stuff can be replaced with Qt-specific equivalents, but the problem is not specific to Qt (indeed, not specific to C++ either, but modern FPUs).Cheers.
-
@Paul-Colby
안녕하세요.우선 바쁘신 와중에 답변주셔서 감사합니다.
답변해주신 부분에 대해 추가적으로 궁금한 내용이 있습니다.
더해지는 값을 double 형 변수에 저장하는 것은 어려울까요?
-
@hlowd said in double 소수점 계산 관련 문의:
더해지는 값을 double 형 변수에 저장하는 것은 어려울까요?
Sure, you can convert the results to floating point numbers at any stage - eg inside the loop, or a the very end. For example:
#include <iomanip> #include <iostream> int main() { uint64_t a = 25; uint64_t sum = 0; for(int i = 0; i < 100000; i++) { sum += a; const double sumAsFloat = sum/100000.0; std::cout << (sum/100000) << '.' << std::setfill('0') << std::setw(5) << (sum%100000) << std::setprecision(10) << " \t[" << sumAsFloat << ']' << std::endl; } }
Outputs:
0.00025 [0.00025] 0.00050 [0.0005] 0.00075 [0.00075] 0.00100 [0.001] 0.00125 [0.00125] 24.99900 [24.999] 24.99925 [24.99925] 24.99950 [24.9995] 24.99975 [24.99975] 25.00000 [25]
Cheers.
PS: In printing both the
uint64_t
anddouble
versions side-by-side, I realised there's was a small error in my previous reply, where the(sum%10000)
should have had another0
, ie(sum%100000)
. I fixed that in the code in this reply :)