Vấn đề của bạn chưa được chỉ định rõ ràng, bạn cần lùi lại và đặt một số câu hỏi.
- Loại đầu vào của bạn là gì?
- Loại nào bạn muốn cho đầu ra của bạn?
- Đối với kết quả nhỏ hơn 1, chính xác bạn muốn làm tròn để làm gì? Bạn có muốn quyền hạn thực tế của 10 hoặc xấp xỉ điểm gần đúng của quyền hạn 10 không? Bạn có biết rằng sức mạnh tiêu cực của 10 không thể được thể hiện chính xác trong dấu phẩy động phải không? Bây giờ chúng ta hãy giả sử rằng bạn muốn xấp xỉ điểm lũy thừa của lũy thừa 10.
- Nếu đầu vào chính xác là công suất 10 (hoặc xấp xỉ điểm nổi gần nhất của công suất 10), thì đầu ra có giống với đầu vào không? Hay nó nên là sức mạnh tiếp theo của 10 lên? "10 -> 10" hoặc "10 -> 100"? Bây giờ hãy giả sử trước đây.
- Giá trị đầu vào của bạn có thể là bất kỳ giá trị có thể có của các loại trong câu hỏi không? hoặc là họ hạn chế hơn.
Trong một câu trả lời khác, nó được đề xuất lấy logarit, sau đó làm tròn lên (hàm trần), sau đó lũy thừa.
def nextpow10(n):
return 10 ** math.ceil(math.log10(n))
Thật không may, điều này bị lỗi làm tròn. Trước hết n được chuyển đổi từ bất kỳ loại dữ liệu nào mà nó có thành số dấu phẩy động chính xác kép, có khả năng gây ra lỗi làm tròn, sau đó logarit được tính có khả năng đưa ra nhiều lỗi làm tròn hơn cả trong tính toán bên trong và kết quả của nó.
Như vậy, tôi không mất nhiều thời gian để tìm một ví dụ mà nó cho kết quả không chính xác.
>>> import math
>>> from numpy import nextafter
>>> n = 1
>>> while (10 ** math.ceil(math.log10(nextafter(n,math.inf)))) > n:
... n *= 10
...
>>> n
10
>>> nextafter(n,math.inf)
10.000000000000002
>>> 10 ** math.ceil(math.log10(10.000000000000002))
10
Về mặt lý thuyết cũng có thể khiến nó thất bại theo hướng khác, mặc dù điều này dường như khó khiêu khích hơn nhiều.
Vì vậy, để có một giải pháp mạnh mẽ cho float và ints, chúng ta cần giả định rằng giá trị của logarit của chúng ta chỉ là gần đúng và do đó chúng ta phải kiểm tra một vài khả năng. Một cái gì đó dọc theo dòng
def nextpow10(n):
p = round(math.log10(n))
r = 10 ** p
if r < n:
r = 10 ** (p+1)
return r;
Tôi tin rằng mã này sẽ cho kết quả chính xác cho tất cả các đối số trong phạm vi độ lớn trong thế giới thực. Nó sẽ phá vỡ đối với số lượng rất nhỏ hoặc rất lớn các loại điểm không nguyên và không dấu phẩy do các vấn đề chuyển đổi chúng thành dấu phẩy động. Các trường hợp đặc biệt của Python đối số nguyên cho hàm log10 trong nỗ lực ngăn chặn tràn, nhưng với một số nguyên đủ lớn, có thể buộc các kết quả không chính xác do lỗi làm tròn.
Để kiểm tra hai triển khai tôi đã sử dụng chương trình thử nghiệm sau.
n = -323 # 10**-324 == 0
while n < 1000:
v = 10 ** n
if v != nextpow10(v): print(str(v)+" bad")
try:
v = min(nextafter(v,math.inf),v+1)
except:
v += 1
if v > nextpow10(v): print(str(v)+" bad")
n += 1
Điều này tìm thấy rất nhiều thất bại trong việc thực hiện ngây thơ, nhưng không có gì trong việc thực hiện được cải thiện.
10
trên xuống, điều này sẽ cần một cái gì đó với ví dụlog10
.