出于学习目的,我正在尝试实现将十进制字符串转换为 64 位浮点数的算法的核心部分。
我使用此页面的解释作为指导:https://www.exploringbinary.com/ Correct-decimal-to-floating-point-using-big-integers
我在 Ruby 中执行此操作,因为 Ruby 的 Integer 类型是作为大整数实现的。
这是我到目前为止所拥有的:
# frozen_string_literal: true
def create_float sign, exponent, mantissa
v = String.new
v << sign.to_s(2)
v << exponent.to_s(2).rjust(11, '0')
v << mantissa.to_s(2).rjust(52, '0')
[v].pack('B*').unpack1('G')
end
def get_scale value
scale = 0
if value >= (2**53)
while value >= (2**53)
value /= 2
scale += 1
end
else
while value < (2**52)
value *= 2
scale += 1
end
end
scale
end
def to_double value, exponent
if exponent >= 0
e = (10**exponent)
t = value * e
s = get_scale t
q = t.div(2**s)
r = t - q * 2**s
z = (52 + s) + 1023
else
e = (10**-exponent)
s = get_scale value.div(e)
t = value * (2**s)
q = t / e
r = t - q * e
z = (52 + -s) + 1023
end
h = e / 2
q += 1 if r > h || r == h && q.odd?
m = q - (2**52)
puts "T: #{t}"
puts "S: #{s}"
puts "Q: #{q}"
puts "R: #{r}"
puts "H: #{h}"
puts "Z: #{z}"
puts "M: #{m}"
create_float 0, z, m
end
# Expected: 1.7976931348623157e+308
# Actual: 1.348269851146737e+308
puts to_double(17_976_931_348_623_158, 292)
该算法对于页面上用作示例的数字(
3.14159
和1.2345678901234567e22
)运行良好,但对于1.7976931348623158e308
则失败。
我认为我的问题可能与舍入部分有关。
q
的 9007199254740992
会失败,但 q
的 9007199254740991
会给我正确的答案。
您的错误在这里:
h = e / 2
h
代表分母的一半,所以这应该是
h = s ** 2 / 2