Safe addition: Difference between revisions

Content added Content deleted
(→‎{{header|C}}: Add solution with Microsoft _controlfp().)
(→‎{{header|REXX}}: Add Ruby using bigdecimal.)
Line 251: Line 251:
numeric digits digits()+digits()%10 /*increase digits by 10%.*/
numeric digits digits()+digits()%10 /*increase digits by 10%.*/
</lang>
</lang>

=={{header|Ruby}}==
The <tt>Float</tt> class provides no way to change the rounding mode. We instead use the <tt>BigDecimal</tt> class from the standard library. <tt>BigDecimal</tt> is a floating-point number of radix 10 with arbitrary precision.

When adding <tt>BigDecimal</tt> values, <tt>a + b</tt> is always safe. This example uses <tt>a.add(b, prec)</tt>, which is not safe because it rounds to <tt>prec</tt> digits. This example computes a safe interval by rounding to both floor and ceiling.

{{libheader|bigdecimal}}
<lang ruby>require 'bigdecimal'
require 'bigdecimal/util' # String#to_d

def safe_add(a, b, prec)
a, b = a.to_d, b.to_d
rm = BigDecimal::ROUND_MODE
orig = BigDecimal.mode(rm)

BigDecimal.mode(rm, BigDecimal::ROUND_FLOOR)
low = a.add(b, prec)

BigDecimal.mode(rm, BigDecimal::ROUND_CEILING)
high = a.add(b, prec)

BigDecimal.mode(rm, orig)
low..high
end

[["1", "2"],
["0.1", "0.2"],
["0.1", "0.00002"],
["0.1", "-0.00002"],
].each { |a, b| puts "#{a} + #{b} = #{safe_add(a, b, 3)}" }</lang>

Output: <pre>1 + 2 = 0.3E1..0.3E1
0.1 + 0.2 = 0.3E0..0.3E0
0.1 + 0.00002 = 0.1E0..0.101E0
0.1 + -0.00002 = 0.999E-1..0.1E0</pre>


=={{header|Tcl}}==
=={{header|Tcl}}==