提供了一种相对通用的方法:
import math
import numba as nb
@nb.njit
def cut_trail(f_str):
cut = 0
for c in f_str[::-1]:
if c == "0":
cut += 1
else:
break
if cut == 0:
for c in f_str[::-1]:
if c == "9":
cut += 1
else:
cut -= 1
break
if cut > 0:
f_str = f_str[:-cut]
if f_str == "":
f_str = "0"
return f_str
@nb.njit
def float2str(value):
if math.isnan(value):
return "nan"
elif value == 0.0:
return "0.0"
elif value < 0.0:
return "-" + float2str(-value)
elif math.isinf(value):
return "inf"
else:
max_digits = 16
min_digits = -4
e10 = math.floor(math.log10(value)) if value != 0.0 else 0
if min_digits < e10 < max_digits:
i_part = math.floor(value)
f_part = math.floor((1 + value % 1) * 10.0 ** max_digits)
i_str = str(i_part)
f_str = cut_trail(str(f_part)[1:max_digits - e10])
return i_str + "." + f_str
else:
m10 = value / 10.0 ** e10
exp_str_len = 4
i_part = math.floor(m10)
f_part = math.floor((1 + m10 % 1) * 10.0 ** max_digits)
i_str = str(i_part)
f_str = cut_trail(str(f_part)[1:max_digits])
e_str = str(e10)
if e10 >= 0:
e_str = "+" + e_str
return i_str + "." + f_str + "e" + e_str
这种方法比纯Python不够精确,而且速度相对较慢(大约慢了3倍):
numbers = (
math.nan, math.inf, -math.inf, 0.0, 1.0, 1.000001, -2000.000014, 1234567890.12345678901234567890,
1234567890.12345678901234567890e10, 1234567890.12345678901234567890e-30,
1.234e-200, 1.234e200
)
k = 32
for number in numbers:
print(f"{number!r:{k}} {str(number)!r:{k}} {float2str(number)!r:{k}}")
%timeit -n 10 -r 10 [float2str(x) for x in numbers]
%timeit -n 10 -r 10 [str(x) for x in numbers]
但在Numba中本地实现str()
用于浮点参数之前,它可以用作解决方法。
请注意,边缘情况处理相对粗略,并且最后1-2位数字的误差相对频繁。