10**100 을 7로 나누고 다시 7을 곱해 보았습니다.

 math.floor() 함수는 유효숫자의 개수 때문에 오차가 좀(?) 많네요.

(float 인스턴스).as_integer_ratio()  메서드로도 확인해 보았습니다.

 

 

>>> import math

>>> help(math.floor)
Help on built-in function floor in module math:

floor(x, /)
    Return the floor of x as an Integral.

    This is the largest integer <= x.
>>> math.floor(1.0/7*1.0E100)*7
9999999999999999916195299569383046603428070211005418059480472676230398615693829843450434335205752832
>>> 10**100 // 7
1428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428
>>> 10**100 // 7 * 7
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999996
>>> (0.7*1E100).as_integer_ratio()
(6999999999999999528519570100600705052013993947706024980124877574781630764975543820898143428537221120, 1)

 

 

 

 

 

 

Posted by Scripter
,

어떤 프로그램 언어를 쓰든 0.1 + 0.2 ≠ 0.3 이 되는 것이 당연(?)합니다.

또한 1.0/(0.1 + 0.2 - 0.3)   ∞ 이 되는 것도 당연(?)합니다.

>>> 0.1 + 0.2 - 0.3
5.551115123125783e-17
>>> 0.1 + 0.2 - 0.3 > 1.0E-17
True
>>> 0.1 + 0.2 - 0.3 > 1.0/10E17
True

0.1 + 0.2 - 0.3 이 1.0E-17 즉 0.000000000000000001 보다 크다고 합니다.

 

이래 가지고서는 부동소수점수의 계산 결과를 어디 까지 믿을 수

있는지 의문입니다.

(보통으로는 배정밀도 부동소수점수는 유효수자 개수가 14개~15개 정도입니다.)

 

다행히 Python 의 fractions 모듈과 decimal 모듈을 사용하면

이런 오류를 쉽게 복구할 수 있습니다.

아래는 Python 3 인터프리터로 실행한 결과입니다.

(fractions.Fraction 객체).limit_denominator() 가 문제 해결의 핵심입니다.

(조금 번거럽네요.)

 

>>> import fractions, decimal, math
>>> a = fractions.Fraction(0.1)
>>> b = fractions.Fraction(0.2)
>>> c = fractions.Fraction(0.3)
>>> a + b == c
False
>>> 0.1 + 0.2 == 0.3
False
>>> a + b > c
True
>>> 0.1 + 0.2 > 0.3
True
>>> a + b - c
Fraction(1, 36028797018963968)
>>> 0.1 + 0.2 - 0.3
5.551115123125783e-17
>>> a2 = a.limit_denominator()
>>> b2 = b.limit_denominator()
>>> c2 = c.limit_denominator()
>>> a2, b2, c2
(Fraction(1, 10), Fraction(1, 5), Fraction(3, 10))
>>> a, b, c
(Fraction(3602879701896397, 36028797018963968), Fraction(3602879701896397, 18014398509481984), Fraction(5404319552844595, 18014398509481984))
>>> a2 + b2
Fraction(3, 10)
>>> "%s" % (a2 + b2)
'3/10'
>>> print("%s" % (a2 + b2))
3/10
>>> c2
Fraction(3, 10)
>>> "%s" % (c2)
'3/10'
>>> print("%s" % (c2))
3/10
>>> a2 + b2 == c2
True
>>> a2 + b2 - c2
Fraction(0, 1)
>>> print(a2 + b2 - c2)
0
>>> print("%s" % (a2 + b2 - c2))
0
>>> print("%d" % (a2 + b2 - c2))
0
>>> print("%d" % (a2 + b2))
0
>>> print("%d" % (c2))
0

 

 

Posted by Scripter
,

부동소수점수에 '를 붙이면 가독성이 좋아 실수를 덜 합니다.

아래의 소스는 MSVC 와 g++ 로 잘 컴파일되고 동일한 실행 결과를 얻습니다.

// Filename: test_cpp_literal.cpp
//
// Compile: cl /utf-8 /EHsc test_cpp_literal.cpp
// Execute: test_cpp_literal
//
//            Or
//
// Compile: g++ -o test_cpp_literal test_cpp_literal.cpp
// Execute:./test_cpp_literal
//
// Output:
//     pie =
//     3.14159
//     3.14159
//     3.141593
//     3.141593e+00
//
//       pie =
//       3.141593
//       3.14159
//       3.141593
//       3.141593e+00
//
//     ee =
//     2.71828
//     2.71828
//     2.718280
//     2.718280e+00
// 
//       ee =
//       2.71828
//       2.71828
//       2.718280
//       2.718280e+00
//
//
// Date: 2023.01.03
//
// Copyright (c) 2023 scrpting.tistory.com
// Liscense: BSD-3


#include <iostream>
#include <iomanip>     // for std::setprecision()
#include <cstdio>

using namespace std;

#if defined(__cplusplus)
double pie = 3.141'593;
#endif

int main()
{
    cout << "pie = " << endl;
    cout << pie << endl;
    printf("%g\n", pie);
    printf("%f\n", pie);
    printf("%e\n", pie);
    cout << endl;

    cout << "  pie = " << endl;
    cout << "  " << setprecision(10) << pie << endl;
    printf("  %lg\n", pie);
    printf("  %lf\n", pie);
    printf("  %le\n", pie);
    cout << endl;

#if defined(__cplusplus)
double ee = 2.718'28;
#endif

    cout << "ee = " << endl;
    cout << ee << endl;
    printf("%g\n", ee);
    printf("%f\n", ee);
    printf("%e\n", ee);
    cout << endl;

    cout << "  ee = " << endl;
    cout << "  " << setprecision(10) << ee << endl;
    printf("  %lg\n", ee);
    printf("  %lf\n", ee);
    printf("  %le\n", ee);
    cout << endl;

    return 0;
}

 

 

 

 

Posted by Scripter
,