Jump to content

Price fraction: Difference between revisions

add Ruby
(Added Fortran)
(add Ruby)
Line 283:
return _cout[ bisect.bisect_right(_cin, centsin) ]</lang>
Other options are to use the fractions or decimals modules for calculating money to a known precision.
 
=={{header|Ruby}}==
A simple function with hardcoded values.
<lang ruby>def rescale_price_fraction(value)
raise ArgumentError, "value=#{value}, must have: 0 <= value < 1.01" if value < 0 || value >= 1.01
if value < 0.06 then 0.10
elsif value < 0.11 then 0.18
elsif value < 0.16 then 0.26
elsif value < 0.21 then 0.32
elsif value < 0.26 then 0.38
elsif value < 0.31 then 0.44
elsif value < 0.36 then 0.50
elsif value < 0.41 then 0.54
elsif value < 0.46 then 0.58
elsif value < 0.51 then 0.62
elsif value < 0.56 then 0.66
elsif value < 0.61 then 0.70
elsif value < 0.66 then 0.74
elsif value < 0.71 then 0.78
elsif value < 0.76 then 0.82
elsif value < 0.81 then 0.86
elsif value < 0.86 then 0.90
elsif value < 0.91 then 0.94
elsif value < 0.96 then 0.98
elsif value < 1.01 then 1.00
end
end</lang>
 
Or, where we can cut and paste the textual table in one place
 
{{works with|Ruby|1.8.7+}} for the <code>String#lines</code> method.
For Ruby 1.8.6, use <code>String#each_line</code>
 
<lang ruby>class Price
ConversionTable = <<-END_OF_TABLE
>= 0.00 < 0.06 := 0.10
>= 0.06 < 0.11 := 0.18
>= 0.11 < 0.16 := 0.26
>= 0.16 < 0.21 := 0.32
>= 0.21 < 0.26 := 0.38
>= 0.26 < 0.31 := 0.44
>= 0.31 < 0.36 := 0.50
>= 0.36 < 0.41 := 0.54
>= 0.41 < 0.46 := 0.58
>= 0.46 < 0.51 := 0.62
>= 0.51 < 0.56 := 0.66
>= 0.56 < 0.61 := 0.70
>= 0.61 < 0.66 := 0.74
>= 0.66 < 0.71 := 0.78
>= 0.71 < 0.76 := 0.82
>= 0.76 < 0.81 := 0.86
>= 0.81 < 0.86 := 0.90
>= 0.86 < 0.91 := 0.94
>= 0.91 < 0.96 := 0.98
>= 0.96 < 1.01 := 1.00
END_OF_TABLE
 
@@conversion_table = ConversionTable.lines.collect do |l|
l.scan(/\d\.\d\d/).collect {|str| str.to_f}
end
 
MIN = @@conversion_table[0][0]
MAX = @@conversion_table[-1][1]
 
def initialize(value)
if value < MIN || value >= MAX
raise ArgumentError, "value=#{value}, must have: #{MIN} <= value < #{MAX}"
end
@standard_value = (@@conversion_table.find do |lower, upper, standard|
value.between?(lower, upper)
end)[2]
end
attr_reader :standard_value
end</lang>
 
And a test suite
<lang ruby>require 'test/unit'
 
class PriceFractionTests < Test::Unit::TestCase
@@ok_tests = [
[0.3793, 0.54],
[0.4425, 0.58],
[0.0746, 0.18],
[0.6918, 0.78],
[0.2993, 0.44],
[0.5486, 0.66],
[0.7848, 0.86],
[0.9383, 0.98],
[0.2292, 0.38],
]
@@bad_tests = [1.02, -3]
 
def test_ok
@@ok_tests.each do |val, exp|
assert_equal(exp, rescale_price_fraction(val))
assert_equal(exp, Price.new(val).standard_value)
end
@@bad_tests.each do |val|
assert_raise(ArgumentError) {rescale_price_fraction(val)}
assert_raise(ArgumentError) {Price.new(val).standard_value}
end
end
 
# demonstrate why it's bad to use floats for money
# 0.06 should map to 0.18, but the floating point representation of 0.06 is
# slightly less, so the conversion returns 0.10 instead
def test_uhoh
assert_equal(0.18, Price.new(0.06).standard_value)
end
end</lang>
 
output
<pre>Loaded suite price_fraction
Started
.F
Finished in 0.018000 seconds.
 
1) Failure:
test_uhoh(PriceFractionTests) [price_fraction.rb:119]:
<0.18> expected but was
<0.1>.
 
2 tests, 23 assertions, 1 failures, 0 errors, 0 skips</pre>
 
=={{header|Tcl}}==
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.