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
You can’t perform that action at this time.