Что не так с моим "поиском цифр" в python? - PullRequest
2 голосов
/ 29 ноября 2009

Я изучаю Python через задачи Project Euler. Для задачи 40 я написал этот код:

import math
i = 1
counter = 0
while counter <= 1000000:
    MMM = int(math.log(i, 10)) + 1
    counter = counter + MMM
    V = math.log(i, 10)
    print(i, counter, MMM, V)
    i += 1

Предполагается вернуть номер, содержащий N-ю цифру. По сути, это должно отслеживать, что произойдет, если я объединю целые числа от 1 до любого числа в другое число. Цель состоит в том, чтобы определить, что такое конкретная цифра. Этот код работает ниже определенного порога, однако к тому времени, когда он достигает миллионной цифры, он становится на единицу. Что мне здесь не хватает? Я видел другие реализации, которые экономят время, но меня больше интересует, почему в какой-то момент счет становится неправильным

Edit:

замена

MMM = int(math.log(i, 10)) + 1

с

MMM = len(str(i))

работает как чемпион!

Хотя было бы неплохо иметь полностью числовое решение, придется подождать, пока я не смогу доверять функциям журнала в Python.

Ответы [ 3 ]

4 голосов
/ 29 ноября 2009

Ошибка с плавающей точкой где-нибудь по пути? Вполне возможно, что в какой-то момент math.log возвращает что-то, что чуть меньше (или больше, в зависимости от направления вашего результата off-by-1) целочисленной границы, и, таким образом, int() усекает его до неправильного значения , Числа с плавающей точкой не являются точными для чисел, которые не могут быть представлены с использованием определенного числа двоичных цифр.

3 голосов
/ 29 ноября 2009

Я думаю, что это проблема линии

MMM = int(math.log(i, 10)) + 1

Некоторые примеры

>>> int(math.log(1000000, 10)) + 1
6
>>> int(math.log(1000001, 10)) + 1
7

В то время как я подозреваю, что вы действительно хотели

>>> len(str(1000000))
7
>>> len(str(1000001))
7

Редактировать На самом деле (как вы и предлагали!) Math.log10 кажется лучшим решением и более соответствует тому, что вы написали изначально

>>> int(math.log10(10000000))
7
>>> int(math.log10(10000001))
7
>>> int(math.log10(10**1000))
1000
>>> int(math.log10(10**10000))
10000
>>> int(math.log10(10**100000))
100000

math.log10 должен сохранять точность лучше, чем math.log(x, 10)

1 голос
/ 29 ноября 2009

Проблема здесь заключается в точности чисел с плавающей запятой, что не удивительно. Я становлюсь нечетким и нечетким по мере увеличения числа цифр. Это основная природа чисел с плавающей запятой, когда вы занимаетесь математикой такого рода, вам нужно знать, какая точность вам нужна.

Стандартный библиотечный модуль decimal позволяет вам точно контролировать точность десятичных значений. Поскольку этот модуль не является аппаратной базой, он позволяет пользователю изменять точность числа с плавающей запятой (по умолчанию это 28 мест). Вы создаете десятичные числа, как показано ниже:

 import decimal
 x = decimal.Decimal(1000000)
 x.log10()

Вы можете изменить требуемую точность следующим образом: decimal.getcontext().prec = 8

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...