Tôi đang cố gắng tìm một thuật toán hiệu quả trong Java để tìm phần thập phân lặp lại của hai số nguyên a
và b
ở đâu a/b
.
ví dụ. 5/7 = 0,714258 714258 ....
Tôi hiện chỉ biết phương pháp phân chia dài.
Tôi đang cố gắng tìm một thuật toán hiệu quả trong Java để tìm phần thập phân lặp lại của hai số nguyên a
và b
ở đâu a/b
.
ví dụ. 5/7 = 0,714258 714258 ....
Tôi hiện chỉ biết phương pháp phân chia dài.
Câu trả lời:
Tôi tin rằng có hai cách tiếp cận chung ở đây, về cơ bản bạn có thể "vũ phu" tìm chuỗi lặp lại dài nhất hoặc bạn có thể giải quyết nó như một vấn đề của lý thuyết số.
Đã lâu rồi tôi mới gặp vấn đề này, nhưng trường hợp đặc biệt (1 / n) là vấn đề # 26 trên Project Euler, vì vậy bạn có thể tìm thêm thông tin bằng cách tìm kiếm các giải pháp hiệu quả cho tên cụ thể đó. Một tìm kiếm dẫn chúng tôi đến trang web của Eli Bendersky, nơi anh ấy giải thích giải pháp của mình . Đây là một số lý thuyết từ trang Mở rộng thập phân của Mathworld :
Bất kỳ phân số không
m/n
đều là định kỳ và có một khoảng thời gianlambda(n)
độc lậpm
,n-1
dài tối đa các chữ số. Nếun
là nguyên tố cùng nhau đến 10, sau đó giai đoạnlambda(n)
củam/n
là một ước củaphi(n)
và có ít nhấtphi(n)
chữ số, trong đóphi
là hàm hàm Ơ-le. Hóa ra đólambda(n)
là thứ tự nhân của 10 (modn
) (Glaisher 1878, Lehmer 1941). Số chữ số trong phần lặp lại của khai triển thập phân của số hữu tỷ cũng có thể được tìm thấy trực tiếp từ thứ tự nhân của mẫu số của nó.
Lý thuyết số của tôi là một chút gỉ tại thời điểm này, vì vậy điều tốt nhất tôi có thể làm là hướng bạn theo hướng đó.
Hãy n < d
và bạn đang cố gắng tìm ra phần lặp lại của n/d
. Gọi p
là số chữ số trong phần lặp lại: sau đó n/d = R * 10^(-p) + R * 10^(-2p) + ... = R * ((10^-p)^1 + (10^-p)^2 + ...)
. Phần ngoặc là một loạt hình học, bằng 1/(10^p - 1)
.
Vì vậy n / d = R / (10^p - 1)
. Sắp xếp lại để có được R = n * (10^p - 1) / d
. Để tìm R, lặp p
từ 1 đến vô cùng và dừng lại ngay khi d
chia đều n * (10^p - 1)
.
Đây là một triển khai trong 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
theo dõi độ dài của chuỗi lặp lại, vì vậy bạn có thể phân biệt giữa 1/9 và 1/99 chẳng hạn)
Lưu ý rằng việc thực hiện này (trớ trêu thay) lặp đi lặp lại nếu việc mở rộng thập phân là hữu hạn, nhưng chấm dứt nếu nó là vô hạn! Tuy nhiên, bạn có thể kiểm tra trường hợp này bởi vì n/d
sẽ chỉ có biểu diễn thập phân hữu hạn nếu tất cả các thừa số nguyên tố d
không phải là 2 hoặc 5 cũng xuất hiện n
.
0.123123... = 123/999
0.714258714258... = 714258/999999 (=5/7)
v.v.
Phân chia dài? : /
Biến kết quả thành một chuỗi, và sau đó áp dụng thuật toán này cho nó. Sử dụng BigDecimal nếu chuỗi của bạn không đủ dài với các loại thông thường.