Я намагаюся знайти ефективний алгоритм на Java, щоб знайти повторювану десяткову частину двох цілих чисел a
і b
де a/b
.
напр. 5/7 = 0,714258 714258 ....
В даний час я знаю лише метод довгого поділу.
Я намагаюся знайти ефективний алгоритм на Java, щоб знайти повторювану десяткову частину двох цілих чисел a
і b
де a/b
.
напр. 5/7 = 0,714258 714258 ....
В даний час я знаю лише метод довгого поділу.
Відповіді:
Я вважаю, що тут є два загальні підходи, ви, по суті, можете "грубою силою" шукати найдовший ряд, що повторюється, або ви можете вирішити це як проблему теорії чисел.
З давніх часів я зіткнувся з цією проблемою, але окремий випадок (1 / n) - це проблема № 26 проекту Project Euler, тому ви, можливо, зможете знайти більше інформації, шукаючи ефективні рішення для цього конкретного імені. Один пошук веде нас на веб-сайт Елі Бендерського, де він пояснює своє рішення . Ось деякі теорії зі сторінки Десятичні розширення Mathworld :
Будь-яка нерегулярна частка
m/n
є періодичною і має період,lambda(n)
незалежний відm
, який є не більшістюn-1
цифр. Якщоn
відносно просте 10, то періодlambda(n)
"m/n
є дільником"phi(n)
і має максимумphi(n)
цифр, деphi
є коефіцієнт підсилення. Виявляється,lambda(n)
це мультиплікативний порядок 10 (модn
) (Glaisher 1878, Lehmer 1941). Кількість цифр у повторюваній частині десяткового розширення раціонального числа також можна знайти безпосередньо з мультиплікативного порядку його знаменника.
Моя теорія чисел на даний момент трохи іржава, тому найкраще, що я можу зробити, - це вказати вам у цьому напрямку.
Нехай n < d
, і ви намагаєтесь з'ясувати повторювану частину n/d
. Нехай p
буде кількість цифр у повторюваній частині: тоді n/d = R * 10^(-p) + R * 10^(-2p) + ... = R * ((10^-p)^1 + (10^-p)^2 + ...)
. Закріплена частина - це геометричний ряд, рівний 1/(10^p - 1)
.
Отже n / d = R / (10^p - 1)
. Переставити для отримання R = n * (10^p - 1) / d
. Щоб знайти R, переведіть цикл p
від 1 до нескінченності та зупиніться, як тільки d
рівномірно розділиться n * (10^p - 1)
.
Ось реалізація в Python:
def f(n, d):
x = n * 9
z = x
k = 1
while z % d:
z = z * 10 + x
k += 1
return k, z / d
( k
відслідковує довжину повторюваної послідовності, тому ви можете розрізняти, наприклад, 1/9 та 1/99)
Зауважте, що ця реалізація (за іронією долі) циклічно назавжди, якщо десяткове розширення кінцеве, але припиняється, якщо вона нескінченна! Ви можете перевірити цей випадок, оскільки n/d
він матиме кінцеве десяткове представлення лише у тому випадку, якщо всі найпростіші коефіцієнти d
, які не є 2 або 5, також є у n
.
0.123123... = 123/999
0.714258714258... = 714258/999999 (=5/7)
і т. Д.
Довгий поділ? : /
Перетворіть результат у рядок, а потім застосуйте до нього цей алгоритм . Використовуйте BigDecimal, якщо ваш рядок недостатньо довгий із звичайними типами.