-1

is_perfect は、数値に完全な n 乗根があるかどうかを調べるメソッドです。
例:
- is_perfect(125,3)は、5^3 が 125 の整数であるため、Trueを返す必要があります
- is_perfect(126,3)は、M^3 が整数である整数 M がないため、Falseを返す必要があります。

def is_perfect(num,power):
    root = 0.00
    p = 0.00
    float(p)
    p = 1.0/power
    root = num**(p)
    print ("root",root,sep = ' ')
    print ("root**power",root**power,sep = ' ')
    check = num -(root**power)
    print (check)
    if check < 1e-14:
        root = math.ceil(root)
    if (root-int(root)) ==0:
        print(num,root,int(root),p,sep = ' ')
        return True
    else:
        print(num,root,int(root),p,sep=' ')
        return False

Python シェルでは、125 の結果が true になるはずのときに、どちらも False を返します。

>>> is_perfect(126,3)
root 5.0132979349645845
root**power 125.99999999999999
1.4210854715202004e-14
126 5.0132979349645845 5 0.3333333333333333
False
>>> is_perfect(125,3)
root 4.999999999999999
root**power 124.99999999999993
7.105427357601002e-14
125 4.999999999999999 4 0.3333333333333333
False
>>> 

メソッドを変更して目的の結果を得るにはどうすればよいですか。

4

3 に答える 3

3

ご覧のとおり、違いは、設定した厳密なしきい値よりもわずかに高くなっています。たとえば、7.105427357601002e-14しきい値の1e-14.

これは、可能な限り整数を使用して機能する、別の単純なアプローチです。

import math

def is_perfect(num, power):
    candidate = num ** (1/power)
    lo_candidate = int(math.floor(candidate))
    hi_candidate = int(math.ceil(candidate))
    return num == lo_candidate**power or num == hi_candidate**power

追加. floor_ ceil_ これは、 (そして十分なメモリがあるint限り:-)...:int(math.floor(candidate)) <= candidate

def is_perfect(num, power):
    float_candidate = num ** (1/power)
    int_candidate = int(math.floor(float_candidate))
    while True:
        powered = int_candidate ** power
        if powered == num: return True
        elif powered > num: return False
        int_candidate += 1

追加**2: そして、これは @Kevin がより読みやすいと考えるバージョンです (意見の問題:-)...:

import itertools

def is_perfect(num, power):
    float_candidate = num ** (1/power)
    for int_candidate in itertools.count(int(math.floor(float_candidate))):
        powered = int_candidate ** power
        if powered == num: return True
        elif powered > num: return False

float_candidate = num ** (1/power)スタイルを別にすると、 ifnumint大きすぎて a に変換できないという問題がまだありfloatます (その行に anOverflowErrorが表示されます)。実生活ではgmpy.root、古き良きパッケージから使用しますが、代替手段として非常に大きな整数の n 乗根を計算する方法gmpyも参照してください。

ただし、知っておく価値のある「汚いトリック」は、最初のステートメントを次のように置き換えることです。

    float_candidate = math.exp(math.log(num)/power)

なぜなら、特に! , in ... (!)を引き起こすmath.log(num)非常に大きな値に対しても計算できるからです。numOverflowErrornum ** (1/power)

于 2014-12-22T17:50:14.700 に答える
2

浮動小数点比較で丸め誤差を回避するには、丸めを行い、整数を使用して最終確認を行う必要があります。

def is_perfect( value, exponent ):
    root = value ** ( 1.0 / exponent )
    root = long( round( root ) )
    return root ** exponent  == value

テストする:

[ x for x in range( 1000 ) if is_perfect( x, 3 ) ]

出力:

[0, 1, 8, 27, 64, 125, 216, 343, 512, 729]

診断テストを作成して、どれだけ高くなるかを確認しましょう。

def test( root, exponent ):  # should print [False, True, False]
    print( [ is_perfect( root ** exponent  + i, exponent ) for i in ( -1, 0, +1 ) ] )

私の場合、指数が 19 の場合、が 14 桁の範囲のどこかに到達するとtest失敗します。rootこの時点でvalue = root**exponentが計算されると、長さvalueは約900 ビットになります。

test( 100000000000000, 19)  # prints [False, True, False]
test( 999999999999999, 19)  # prints [False, False, False]
于 2014-12-22T18:11:08.530 に答える