Created
July 16, 2009 17:18
-
-
Save raggi/148543 to your computer and use it in GitHub Desktop.
bigdecimal char_round
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "benchmark" | |
require 'bigdecimal' | |
class BigDecimal | |
# raggi after hint from apeiros (round 1) | |
def raggi_round(n = 15) | |
s = to_s('f')[0,n+1] | |
i = s.index('.') | |
dp = n - i | |
dp = 0 if dp < 0 | |
s = round(dp).to_s('f')[0,n+1] | |
s = s[n,1].to_i >= 5 ? s[0,n].succ : s[0,n] | |
if s[-1,1] == '.' | |
s[0,n-1] | |
else | |
s | |
end | |
end | |
# apeiros round 5 | |
def apeiros_round(n) | |
int, frac = *to_s("f").split(".") | |
case int.length | |
when 0..(n - 2) | |
round(n-int.length-1).to_s("f") | |
when (n - 1)..n | |
round(0).to_s("f").split(".").first | |
else | |
raise SomeError | |
end | |
end | |
end | |
def call(meth) | |
BigDecimal("1234567890.1234567890").send(meth, 10) | |
BigDecimal("1234567890.1234567890").send(meth, 11) | |
BigDecimal("1234567890.1234567890").send(meth, 12) | |
BigDecimal("1234567890.1234567890").send(meth, 13) | |
BigDecimal("1234567890.9876543210").send(meth, 10) | |
BigDecimal("1234567890.9876543210").send(meth, 11) | |
BigDecimal("1234567890.9876543210").send(meth, 12) | |
BigDecimal("1234567890.9876543210").send(meth, 13) | |
end | |
TESTS = 10_000 | |
Benchmark.bmbm do |results| | |
results.report("raggi:" ) { TESTS.times { call(:raggi_round) } } | |
results.report("apeiros:") { TESTS.times { call(:apeiros_round) } } | |
end | |
# Rehearsal -------------------------------------------- | |
# raggi: 0.780000 0.020000 0.800000 ( 0.850318) | |
# apeiros: 1.240000 0.030000 1.270000 ( 1.340230) | |
# ----------------------------------- total: 2.070000sec | |
# | |
# user system total real | |
# raggi: 0.770000 0.020000 0.790000 ( 0.842681) | |
# apeiros: 1.240000 0.030000 1.270000 ( 1.336721) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "test/unit" | |
require "bigdecimal" | |
# Maybe I'm being dumb, but I can't find a clean way to do this without | |
# writing a state machine that walks backward over the string. Fork and fixme! | |
class BigDecimal | |
# raggi after hint from apeiros (round 1) | |
def char_round(n = 15) | |
s = to_s('f')[0,n+1] | |
i = s.index('.') | |
dp = n - i | |
dp = 0 if dp < 0 | |
s = round(dp).to_s('f')[0,n+1] | |
s = s[n,1].to_i >= 5 ? s[0,n].succ : s[0,n] | |
if s[-1,1] == '.' | |
s[0,n-1] | |
else | |
s | |
end | |
end | |
# # apeiros round 1 | |
# def char_round(n = 15) | |
# bd = self | |
# int, frac = bd.to_s('f').split("."); | |
# raise if int.length > n; | |
# return int if int.length >= n-1; | |
# bd.round(n-1-int.length).to_s("f") | |
# end | |
# | |
# # apeiros round 2 | |
# def char_round(n) | |
# int, frac = *to_s("f").split(".") | |
# raise if int.length > n | |
# int.length == (n-1) ? int : round(n-int.length-1).to_s("f") | |
# end | |
# # apeiros round 3 | |
# def char_round(n) | |
# int, frac = *to_s("f").split(".") | |
# raise if int.length > n | |
# return int if int.length == n-1 | |
# int.length == (n-1) ? int : round(n-int.length-1).to_s("f") | |
# end | |
# # apeiros round 4 | |
# def char_round(n) | |
# int, frac = *to_s("f").split(".") | |
# case int.length | |
# when 0..(n-2) | |
# int.length == (n-1) ? int : round(n-int.length-1).to_s("f") | |
# when n-1 | |
# int | |
# else | |
# return int | |
# end | |
# end | |
# # ReinH round 1 | |
# def char_round(n) | |
# int, frac = *to_s("f").split(".") | |
# case int.length | |
# when 0..(n - 2) | |
# round(n-int.length-1).to_s("f") | |
# when (n - 1)..n | |
# int | |
# else | |
# raise SomeError | |
# end | |
# end | |
# apeiros round 5 | |
def char_round(n) | |
int, frac = *to_s("f").split(".") | |
case int.length | |
when 0..(n - 2) | |
round(n-int.length-1).to_s("f") | |
when (n - 1)..n | |
round(0).to_s("f").split(".").first | |
else | |
raise SomeError | |
end | |
end | |
end | |
class TestCharRound < Test::Unit::TestCase | |
def test_char_round_down_int_result | |
assert_equal "1234567890", BigDecimal("1234567890.1234567890").char_round(10) | |
end | |
def test_char_round_down_decimal_skip | |
assert_equal "1234567890", BigDecimal("1234567890.1234567890").char_round(11) | |
end | |
def test_char_round_down_decimal_round | |
assert_equal "1234567890.1", BigDecimal("1234567890.1234567890").char_round(12) | |
end | |
def test_char_round_down_decimal_round_long | |
assert_equal "1234567890.12", BigDecimal("1234567890.1234567890").char_round(13) | |
end | |
def test_char_round_up_int_result | |
assert_equal "1234567891", BigDecimal("1234567890.9876543210").char_round(10) | |
end | |
def test_char_round_up_decimal_skip | |
assert_equal "1234567891", BigDecimal("1234567890.9876543210").char_round(11) | |
end | |
def test_char_round_up_decimal_round | |
assert_equal "1234567891.0", BigDecimal("1234567890.9876543210").char_round(12) | |
end | |
def test_char_round_up_decimal_round_long | |
assert_equal "1234567890.99", BigDecimal("1234567890.9876543210").char_round(13) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment