어떤 프로그램 언어를 쓰든 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
,

지난 2021년 12월 6일에 Python 3.10.1 이 출시되었다.

 

설치하자 마자 인터프리터 쉘로 간단히 테스트해 보았다.

 

Python 3.10.1 (tags/v3.10.1:2cd268a, Dec  6 2021, 19:10:37) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> print("Hello~")
Hello~
>>> for i in range(11):
...     print(2**i)
...
1
2
4
8
16
32
64
128
256
512
1024
>>> import math
>>> math.factorial(10)
3628800
>>> math.gamma(11)
3628800.0
>>> math.lgamma(11)
15.104412573075514
>>> math.log(math.gamma(11))
15.104412573075516
>>> math.exp(10)
22026.465794806718
>>> 10**10
10000000000
>>> 10.0**10.0
10000000000.0
>>> math.pow(10.0, 10.0)
10000000000.0
>>> math.exp(10.0*math.log(10.0))
10000000000.00004
>>> math.sqrt(10)
3.1622776601683795
>>> math.cbrt(10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'math' has no attribute 'cbrt'
>>> math.tan(1)
1.5574077246549023
>>> math.atan(1)
0.7853981633974483
>>> 4*(math.atan(1.0/5)*4 - math.atan(1.0/239))
3.1415926535897936
>>> math.pi
3.141592653589793
>>> math.e
2.718281828459045
>>> math.exp(1)
2.718281828459045
>>> (math.exp(1) - math.exp(-1))/2
1.1752011936438014             ^
SyntaxError: unmatched ')'
>>> math.sinh(1)
1.1752011936438014
>>> math.atan(1)
0.7853981633974483
>>> math.gcd(625, 1000)
125
>>> quit()

 

아직 세제곱근(cube root) 구하는 math.cbrt(float) 함수는 구현되지 않았다.

 

-----------------------------------------------------------------------------

Union 타입 생성  연산자 '|' 기 Python 3.10.x 에 추가되었다.


>>> # Union 타입을 매개변수로 방아 Union 타입을 리턴허눈 험수
>>> # def f(list: list[Union[int, str]], param: Optional[int]) -> Union[float, str]

>>>  # 대신, 다음 구문으로 가능

>>> def f(list: list[int | str], param: int | None) -> float | str:
.>>> ..     pass
...


>> int 타입과 list[int] 타입의 Union 타입

>>> str(int | list[str])
'int | list[str]'



>>> 두 int 타입의 Union 타입
>>> str(int | int)
"<class 'int'>"


>>> Union 타입을 이용헌 인스턴스 확인

>>> isinstance("", int | str)
True


>>> Union 타입을 이용헌 상속 확인

>>> issubclass(bool, int | float)
True

 

>>> # 클래스 상속과 Union 타입 생성 연산자 확인
>>> class M(type):
...         def __or__(self, other): return "Hello"
...
>>> class C(metaclass=M): pass
...

>>> C | int
'Hello'


>>> int | C
int | __main__.C

 

-------------------------------------------------

다음은 아직은 아니지만 다음 릴리즈에 추가될 것 중의 하나이다.

우선 다음 내용을 test,py 라는 파일명으로 자장하고,

x = {'a':{'b':{'c':None}}}
x['a']['b']['c']['d'] = 1

 

프롬프트> python test,py

명령으로 실행합니다. 그러면 다음 에러 메시지가 나온다.

Traceback (most recent call last):
  File "test.py", line 2, in <module>
    x['a']['b']['c']['d'] = 1
TypeError: 'NoneType' object does not support item assignment

 

이 에러 메시지 만으로는 시퀀스 타입 자료에 어느 것이 None 인지 알 수가 없다.

다음 릴리즈에서는 에러 메시지가

Traceback (most recent call last):
  File "test.py", line 2, in <module>
    x['a']['b']['c']['d'] = 1
    ~~~~~~~~~~~^^^^^
TypeError: 'NoneType' object is not subscriptable

로 출력된다. (이는 핸재 Python Pre-Release 3.11.0a3 에서 확인되옸다.)

 

 

 

 

 

 

Posted by Scripter
,

Lanczos 알고리즘은 Stirlng 공식에 의한 알고리즘 보다 정밀하며, 십진수로 유효숫자 약 15자리 까지는 정확하게 계산해 준다.  단지 exp 함수를 이용하는 부분에서는 exp 함수의 구현에 따라 오차가 더 있을 수 있다.


#!/usr/bin/env python
# -*- encoding:utf-8 -*-

# Filename: testLanczos-01.py
#
#           An approximation for the gamma function by using the Lanczos algorithm
#
# Execute: python testLanczos-01.py
#         or
# Execute: ./testLanczos-01.py
#
# See: http://en.wikipedia.org/wiki/Lanczos_approximation
# See:http://www-history.mcs.st-and.ac.uk/Biographies/Lanczos.html
# See: http://www.thinbasic.com/community/showthread.php?11279-Gamma-function

from cmath import *
 
# Coefficients used by the GNU Scientific Library
g = 7
p = [0.99999999999980993, 676.5203681218851, -1259.1392167224028,
     771.32342877765313, -176.61502916214059, 12.507343278686905,
     -0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7]
 
def gamma(z):
    z = complex(z)
    # Reflection formula
    if z.real < 0.5:
        return pi / (sin(pi*z)*gamma(1-z))
    else:
        z -= 1
        x = p[0]
        for i in range(1, g+2):
            x += p[i]/(z+i)
        t = z + g + 0.5
        return sqrt(2*pi) * t**(z+0.5) * exp(-t) * x

def factorial(n):
    if n < 2:
        return 1
    else:
        k = 1
        if n % 2 == 0:
            for i in xrange(n/2):
                k *= (i + 1) * (n - i)
        else:
            for i in xrange(n/2):
                k *= (i + 1) * (n - 1 - i)
            k *= n
        return k

def facto(n):
    if n < 2:
        return 1
    else:
        k = 1
        for i in xrange(2, n + 1):
                k *= i
        return k

if __name__ == "__main__":
    print "gamma(10) = 9! = %s asymptotically" % gamma(10)
    # print "gamma(101) = 100! = %16s asymptotically" % gamma(101)
    print "gamma(101) = 100! = %16s asymptotically" % "{0.real:.15f}{0.imag:+.5f}j".format(gamma(101))

    for i in range(11):
        print "%d! = %d" % (i, factorial(i))

    i = 100
    print "factorial(%d) = %d! = %d" % (i, i, factorial(i))
    print "facto(%d) = %d! = %d" % (i, i, facto(i))

"""
Output:
gamma(10) = 9! = (362880+0j) asymptotically
gamma(101) = 100! = 9.33262154439379e+157+0.00000j asymptotically
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800
factorial(100) = 100! = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
facto(100) = 100! = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
"""



Posted by Scripter
,