Найти - Пользователи
Полная версия: Длинная арифметика
Начало » Python для новичков » Длинная арифметика
1 2
UncleFather
Всем привет!
Подскажите, пожалуйста, кто знает почему на Python 3.6 при попытке посчитать длинные целые числа, получается неверный ответ:
print(int(-9999999999 * 10000000002 / 2))
print(int(-(10**10-1) * (10**10+2) / (2**1)
>>-50000000005000003584
>>-50000000005000003584

А должно быть
-50000000004999999999
в обоих случаях.

Спасибо.
FishHook
Во втором питоне деление по дефолту целочисленное, то есть 10000000002 / 2 - целое, а в третьем результат деления по умолчанию дает float. Если вы точно знаете, что результат деления будет целым, то можно делить так 10000000002 // 2
UncleFather
FishHook
Во втором питоне деление по дефолту целочисленное, то есть 10000000002 / 2 - целое, а в третьем результат деления по умолчанию дает float. Если вы точно знаете, что результат деления будет целым, то можно делить так 10000000002 // 2

Спасибо, так сработало. Про целочисленное деление я что-то сразу не сообразил.

Но все же получается, если я буду считать в типе float, то ответ получится неверный. Почему так? Разве питон, когда считает во floate, отбрасывает какую-то часть числа?
FishHook
UncleFather
Почему так? Разве питон, когда считает во floate, отбрасывает какую-то часть числа?

Потому что у дробного числа всегда есть предел точности. Даже если вы возьмете ооооочень большое целое число, вы всегда знаете сколько байт памяти нужно, чтобы хранить это число. А сколько байт нужно для хранения иррациональных значений? Разумеется, всегда есть предел точности вычислений при операциях с float и double.
UncleFather
да как-то напрягает, когда java выдает одинаковые ответы
System.out.println(new BigDecimal("1000000000000000000000000002").divide(BigDecimal.valueOf(2)));
>>500000000000000000000000001
System.out.println(new BigInteger("1000000000000000000000000002").divide(BigInteger.valueOf(2)));
>>500000000000000000000000001

а питон - разные:
print(int(1000000000000000000000000002 / 2))
500000000000000006643777536
print(int(1000000000000000000000000002 // 2))
>>500000000000000000000000001

я понимаю, когда отбрасывается дробная часть…. но целую-то часть отбрасывать незачем. В ней же число знаков не бесконечно.

Получается, что если хочешь в питоне посчитать огроооомное число, но при этом результат деления не будет целым, то потеряешь в точности всё после 16-го знака? Или как-то можно в питоне считать (делить) числа, которые длиннее 16 знаков, получая нормальные ответы?

Спасибо за Ваши ответы и советы))).

FishHook
UncleFather
я понимаю, когда отбрасывается дробная часть…. но целую-то часть отбрасывать незачем.

Это потому что вы плохо представляете, как float хранится в памяти. Вот почитайте. Грубо говоря, float - это маленькая голова целого, длинный хвост дроби и степень двойки. Когда вы приводите float к целому вы побитово сдвигаете хвост на степень знаков.
FishHook
UncleFather
да как-то напрягает, когда java выдает одинаковые ответы
Потому что Decimal. Очень странно, что в java вы с удовольствием используете этот тип, а в питоне не хотите

    
from decimal import Decimal
print((Decimal(1000000000000000000000000002) / 2))
>>>500000000000000000000000001
UncleFather
FishHook
Потому что Decimal. Очень странно, что в java вы с удовольствием используете этот тип, а в питоне не хотите
Спасибо))), просто не знал про Decimal в питоне.
Значит, если мы просто считаем 1000000000000000000000000002 / 2, то питон считает это как обычный float и после преобразования int(1000000000000000000000000002 / 2) мы получим именно округленный float.
В то время, как Decimal(1000000000000000000000000002) сразу говорит интерпретатору, что считать нужно с такой точностью, сколько в числе знаков.

FishHook
Это потому что вы плохо представляете, как float хранится в памяти. Вот почитайте. Грубо говоря, float - это маленькая голова целого, длинный хвост дроби и степень двойки. Когда вы приводите float к целому вы побитово сдвигаете хвост на степень знаков.
Это-то я помню. Для меня вопрос заключался немного в другом. А именно - если везде пишут, что длинная арифметика встроена в питон, то значит, что под переменную float и int питон должен выделять не 32 бита, как в других языках (и даже не 64), а столько, сколько потребуется. Если для других языков объем памяти для хранения переменных четко прописан и найти это в сети достаточно легко, то для питона, если это где-то и записано, то еще нужно постараться найти. А поскольку сразу не нашел - отсюда и заблуждение.
Короче - нужно мне учить матчасть.
Спасибо еще раз за Ваши советы, теперь появилась какая-то ясность.

Последний вопрос - если есть подозрение, что мы выскочим из long-а, то в формуле, там где происходит первое действие, нужно прописать Decimal, а остальная часть уже сама будет считаться как Decimal?
g = 9999999999999999999999
Decimal(1 + g) / 2 * g
FishHook
UncleFather
что под переменную float и int питон должен выделять не 32 бита, как в других языках (и даже не 64), а столько, сколько потребуется
Ну тогда простая операция 1 / 3 сожрет всю память вашего компьютера
FishHook
UncleFather
Последний вопрос - если есть подозрение, что мы выскочим из long-а, то в формуле, там где происходит первое действие, нужно прописать Decimal, а остальная часть уже сама будет считаться как Decimal?
В питоне можно переопределять операторы. Понятно что Decimal(x) * 4 -> умножение вызовет метод у объекта Decimal и этот метод вернет опять Decimal. А 4 * Decimal(x) - нет.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB