Python - операции Java Math дают разные результаты - PullRequest
0 голосов
/ 18 января 2019

Я занимаюсь большим количеством математики как на Java, так и на Python. Суммы одинаковы, но результаты разные.

python_n1 = int(math.floor(math.pow(int((int(361) * (int(4900 + 4489))) * int(4356)), int(6))))
BigInteger Java_n1 = (x[20].multiply(x[7].add(x[15])).multiply(x[10])).pow(6);

python_simple_sum = 14764352724**6 #or math.pow(14764352724, 6)
BigInteger Java_simple_sum = new BigInteger("14764352724 ").pow(6)

Python Ответы = 10358251994780842724998096890217137953445700726699419360034816 Java ответы = 10358251994780842575401275783021915748383652186833068257611776

Java получает правильный результат, а python - нет. Насколько я знаю, я не использую числа с плавающей точкой. В чем проблема здесь.

1 Ответ

0 голосов
/ 18 января 2019

Когда вы делаете

int(math.pow(14764352724, 6))

вы получаете большое число, возведенное в степень, но используя метод с плавающей запятой, даже если аргументы являются целыми числами. Преобразование в целое число теряет точность (исходный результат - число с плавающей точкой: 1.0358251994780843e+61)

Когда вы делаете

14764352724**6

вы получаете большое число, возведенное в степень с использованием метода двоичной степени , использующего только целочисленное умножение.

Таким образом, второй результат точен, тогда как первый не

>>> int(math.pow(14764352724,6))
10358251994780842724998096890217137953445700726699419360034816   # wrong
>>> 14764352724**6
10358251994780842575401275783021915748383652186833068257611776   # correct

Давайте попробуем разобрать функции ** и math.pow:

import dis,math

def test(n):
    return n ** 3

def test2(n):
    return math.pow(n,3)

dis.dis(test)
dis.dis(test2)
* * Выход тысяча двадцать-один * * одна тысяча двадцать-дв
  4           0 LOAD_FAST                0 (n)
              3 LOAD_CONST               1 (3)
              6 BINARY_POWER
              7 RETURN_VALUE

  7           0 LOAD_GLOBAL              0 (math)
              3 LOAD_ATTR                1 (pow)
              6 LOAD_FAST                0 (n)
              9 LOAD_CONST               1 (3)
             12 CALL_FUNCTION            2 (2 positional, 0 keyword pair)
             15 RETURN_VALUE

Как видите, функции не эквивалентны. BINARY_POWER вызывается в первом случае. Эта функция может точно выполнять целочисленное умножение , когда параметры целочисленные :

BINARY_POWER ()

Реализует TOS = TOS1 ** TOS

Двоичная мощность дает то же значение, что и math.pow, когда параметры не являются целыми:

>>> 14764352724**6.0
1.0358251994780843e+61
>>> int(14764352724**6.0)
10358251994780842724998096890217137953445700726699419360034816

Примечание: что, вероятно, добавляет к путанице встроенный метод pow, который отличается от math.pow (и переопределяется последним при использовании from math import pow), но эквивалентно ** оператору при использовании без аргумента по модулю:

pow (x, y [, z])

Верните x в степень y; если присутствует z, вернуть x в степень y по модулю z (вычисляется более эффективно, чем pow (x, y)% z). Форма с двумя аргументами pow (x, y) эквивалентна использованию оператора степени : x ** y.

...