Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
POC of accurate_to_s
require "bigdecimal"
class Float
HEX_FORMAT = /(-?)0x([01])\.?([0-9a-f]*)p([+-][0-9]*)/
BIG_DECIMAL_2 = BigDecimal(2)
def accurate_to_s
bin_str = "%a" % [self]
mat = HEX_FORMAT.match bin_str
sgn, msbit, bits, ex = mat[1, 4]
if msbit == "0" then
unless bits == "" and ex == "+0" then
raise "assertion error"
end
return "#{sgn}0"
end
result = BigDecimal((sgn+msbit+bits).to_i 16)
ex = ex.to_i - bits.length * 4
case ex <=> 0
when 1 then # ex > 0
result *= 2**ex
when -1 then # ex < 0
result *= BIG_DECIMAL_2**ex
end
return result.to_s
end
end
class Rational
BIG_DECIMAL_2 = BigDecimal(2)
BIG_DECIMAL_5 = BigDecimal(5)
def accurate_to_s
deno = self.denominator
if deno == 1 then
return self.numerator.to_s
end
tmp = deno
t_2 = 0
t_5 = 0
loop {
q, r = tmp.divmod 2
break if r != 0
tmp = q
t_2 += 1
}
loop {
q, r = tmp.divmod 5
break if r != 0
tmp = q
t_5 += 1
}
if tmp != 1 then
return nil
end
result = BigDecimal(self.numerator)
result *= BIG_DECIMAL_2**-t_2
result *= BIG_DECIMAL_5**-t_5
return result.to_s
end
end
alias BigDecimal_ORIG BigDecimal
def BigDecimal val, *args
if args == [nil] then
if val.respond_to? :accurate_to_s then
result = val.accurate_to_s
if result then
return BigDecimal_ORIG(result)
end
end
end
BigDecimal_ORIG val, *args
end
if $0 == __FILE__
x = 0.1
puts BigDecimal(x, nil).to_s
puts BigDecimal(Rational(x), nil).to_s
end
@metanest

This comment has been minimized.

Copy link
Owner Author

@metanest metanest commented Apr 19, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment