在 Ruby 中使用大整数将小数正确转换为浮点

问题描述 投票:0回答:1

出于学习目的,我正在尝试实现将十进制字符串转换为 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
会给我正确的答案。

ruby floating-point decimal
1个回答
0
投票

您的错误在这里:

h = e / 2

h
代表分母的一半,所以这应该是

h = s ** 2 / 2 
© www.soinside.com 2019 - 2024. All rights reserved.