Ruby doesn't know how to multiply

From: Michael W. Ryder [mailto:[email protected]] :

My simple calculator is more precise for some math operations than my

expensive PC. Maybe we need to implement something like

General Decimal

Arithmetic which is available for C++ and Java at

http://www2.hursley.ibm.com/decimal/ in Ruby. It may be as simple as

writing wrappers for the operations, I haven’t had to time to look

closer at the package.

have you tried bigdecimal?

irb(main):001:0> require ‘bigdecimal’
=> true
irb(main):002:0> a=BigDecimal(“14.95”)
=> #BigDecimal:2867a5c,‘0.1495E2’,8(8)
irb(main):003:0> b=BigDecimal(“0.6”)
=> #BigDecimal:28614b8,‘0.6E0’,4(8)
irb(main):004:0> c=BigDecimal(“8.97”)
=> #BigDecimal:28e47b4,‘0.897E1’,8(8)
irb(main):005:0> d=BigDecimal(“8.970000001”)
=> #BigDecimal:28dffe8,‘0.8970000001E1’,16(16)
irb(main):006:0> ab == c
=> true
irb(main):007:0> a
b == d
=> false
irb(main):008:0> c == 8.97
=> true

bigdecimal notation is very handy for calculator-like applications since
the raw input usually is of type string.

kind regards -botp

Hi,

On 6/22/07, Yukihiro M. [email protected] wrote:

|I tried this in Delphi, smalltalk and oracle SQL and got the correct
|result.

Interesting. There are a few ways to get the “correct” result.

  • fixed point number
  • base 10 floating numbers
  • comparison with epsilon

Oracle uses base 100 floating numbers.
http://download-west.oracle.com/docs/cd/B19306_01/appdev.102/b14250/oci03typ.htm#sthref431

On 6/22/07, Michael W. Ryder [email protected] wrote:

I’m not trying to denigrate the project but it looks like it is still in
alpha stage while the IBM project seems to have been releasing
production code for a while. It also is an IEEE standard, which may or
may not mean anything.

Um… BigDecimal part of the ruby standard library. What is ‘alpha’
about it?

Peña wrote:

irb(main):006:0> a*b == c

I’m not trying to denigrate the project but it looks like it is still in
alpha stage while the IBM project seems to have been releasing
production code for a while. It also is an IEEE standard, which may or
may not mean anything.
I hadn’t known about the bigdecimal project before and may try comparing
the results of it to the general decimal arithmetic package if I get
time.

Gregory B. wrote:

On 6/22/07, Michael W. Ryder [email protected] wrote:

I’m not trying to denigrate the project but it looks like it is still in
alpha stage while the IBM project seems to have been releasing
production code for a while. It also is an IEEE standard, which may or
may not mean anything.

Um… BigDecimal part of the ruby standard library. What is ‘alpha’
about it?

My mistake. When I entered bigdecimal in the search screen at Ruby
Forge it pointed me to the long decimal package. Searching for
bigdecimal on ruby-lang.org came up with zero results. Where do I find
more information on bigdecimal as it isn’t listed in the on-line version
of Pickaxe?

Michael W. Ryder wrote:

I think we have a difference of understanding of what fixed point means.
I look at fixed point numbers meaning something like 1057 means 10.57
in the real world. I was thinking more of something that shifted the
floating point number to remove the fractions and later replaced the
decimal point in the correct position, which I do not consider to be
fixed point math.

Basically you are thinking of

require “rational”
=> true

Rational(1057,100).to_f
=> 10.57

Daniel

On 6/22/07, Michael W. Ryder [email protected] wrote:

My mistake. When I entered bigdecimal in the search screen at Ruby
Forge it pointed me to the long decimal package. Searching for
bigdecimal on ruby-lang.org came up with zero results. Where do I find
more information on bigdecimal as it isn’t listed in the on-line version
of Pickaxe?

http://www.ruby-doc.org/stdlib/libdoc/bigdecimal/rdoc/index.html

There is also a page in the stdlib section of Pickaxe II

Daniel DeLorme wrote:

=> true

Rational(1057,100).to_f
=> 10.57

Daniel

I have been using Business Basic for over 25 years and it is what I
consider fixed point. For example, entering ‘Print 14.95*.6’ results in
8.97. The language uses a set precision which can be changed. For
example if I tell it to print 120*.000003 with the default precision of
2 it displays 0. If I change the precision to 6 and tell it to print
the same thing it displays .00036. The computer stores the result in
the precision at the time of the operation so entering ‘a=120*.000003’
in precision 2 stores 0 in a. Changing the precision to 6 afterwards
still shows that 0 is stored in a. This is not like Ruby using printf
where different formats show different results.

On 6/21/07, Yukihiro M. [email protected] wrote:

  • fixed point number
  • base 10 floating numbers
  • comparison with epsilon

Does anyone know how these languages get the correct result?

matz,

I don’t know which Smalltalk he used, but I just tried it in Squeak
and it evalutes to false, just like in Ruby.

Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

On 6/21/07, Adriano F. [email protected] wrote:

On 6/21/07, juan pedro meriño [email protected] wrote:

You are rigth James, but you can better reponse why is a floating point
error?

Some numbers (like 0.1) cannot be represented exactly in binary with a
finite number of bits (because 0.1[base 10] =
0.0001100110011001100110011…[base 2]) and when they are represented
(as it happens with floating point representations), they lose
precision

Actually in any base there are fractions which cannot be represented
with a
FINITE number of digits. For instance in base 10:

1/3 = 0.33333333333…


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

From: Michael W. Ryder [mailto:[email protected]]

I have been using Business Basic for over 25 years and it is what I

consider fixed point. For example, entering ‘Print 14.95*.6’

results in

8.97. The language uses a set precision which can be changed. For

example if I tell it to print 120*.000003 with the default

precision of

2 it displays 0. If I change the precision to 6 and tell it to print

the same thing it displays .00036. The computer stores the result in

the precision at the time of the operation so entering

‘a=120*.000003’

in precision 2 stores 0 in a. Changing the precision to 6 afterwards

still shows that 0 is stored in a. This is not like Ruby

using printf

where different formats show different results.

w ruby’s bigdecimal, you can be precise as much as you want (limit is on
the computer’s power and the programmer’s imagination). it’s being used
not only in business but also in scientific labs (that is as far as what
i’ve heard fr ruby jap gossip/chat rooms)

this is one stupid example,

irb(main):013:0> a=BigDecimal(“0.0”+"0"100+“1”)
=> #BigDecimal:28b4dd4,‘0.1E-101’,4(108)
irb(main):014:0> a+1
=> #<BigDecimal:28b26ec,‘0.1000000000 0000000000 0000000000 0000000000
000000000
0 0000000000 0000000000 0000000000 0000000000 0000000000
001E1’,108(140)>
irb(main):015:0> (a+1).to_s
=>
“0.10000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000001E1”
irb(main):016:0> (a+1).to_s.size
=> 107
irb(main):017:0> (a+1)
(a+1)
=> #<BigDecimal:28a995c,‘0.1000000000 0000000000 0000000000 0000000000
000000000
0 0000000000 0000000000 0000000000 0000000000 0000000000 0020000000
0000000000 0
000000000 0000000000 0000000000 0000000000 0000000000 0000000000
0000000000 0000
000000 00001E1’,208(276)>
irb(main):018:0>
irb(main):019:0> ((a+1)(a+1)).to_s
=>
“0.10000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000002000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000001E1”
irb(main):020:0> ((a+1)
(a+1)).to_s.size
=> 209

it’s inspiring. really.
kind regards -botp

On 6/23/07, Peña, Botp [email protected] wrote:

‘a=120*.000003’

Yes, basically what you are dealing with is how the object is
represented, and not how it really is:

irb(main):001:0> 1.0/9.0 + 8.0/9.0 == 1
=> true
irb(main):002:0> 1.0/9.0
=> 0.111111111111111
irb(main):003:0>

Pretty obvious what’s going on there without looking at the source
code. If you ‘really’ want it the way it is, you use BigDecimal.
Again, LCD factor. What is the easiest way to appease your
programmer? You give them what you think they expect most of the
time. Most people don’t need a BigDecimal.

Todd

On 6/22/07, Rick DeNatale [email protected] wrote:

On 6/21/07, Yukihiro M. [email protected] wrote:

matz,

I don’t know which Smalltalk he used, but I just tried it in Squeak
and it evalutes to false, just like in Ruby.
Same for Gnu Smalltalk.
R.

MenTaLguY:

The best you can do is test whether the result is
within some interval (epsilon) of the expected result:

( ( 14.95 * 0.6 ) - 8.97 ).abs < 1e-6

(Here, we’ve chosen 1e-6 as our epsilon, which is arbitrary but
probably “small enough” in this case. For mathematically intensive
code, you may need to be more careful.)

Any particular reason against using Float::EPSILON here? :slight_smile:

Maybe Float#== could simply be extended to consider the above? That
would most probably open another can of worms, though, and extending
Float#<=> would open yet another, I guess.

– Shot

Peña wrote:

w ruby’s bigdecimal, you can be precise as much as you want (limit is on the computer’s power and the programmer’s imagination). it’s being used not only in business but also in scientific labs (that is as far as what i’ve heard fr ruby jap gossip/chat rooms)

As a matter of fact, the BigDecimal library comes with some scientific
routines as standard equipment, such as LU decomposition and Newton
iteration. That isn’t a great surprise to me, having once earned a
living programming one of the most popular scientific machines ever, the
IBM 1620, which was a variable-length decimal computer. I don’t
remember, but I think the SIMH project has an emulator:

http://simh.trailing-edge.com/

On 6/24/07, Stefan R. [email protected] wrote:

I think Float#== as it is is fine. Arguably it could use delta
comparison with Float::EPSILON and leave the exact comparison to eql?
But I’d like it if Float#in_delta(other, delta=Float::EPSILON) was in
core (personally I add it in my libs as Numeric#in_delta).

I’d prefer in_delta?, but I think this is a great idea. Maybe you
should submit an RCR?

Shot (Piotr S.) wrote:

MenTaLguY:

The best you can do is test whether the result is
within some interval (epsilon) of the expected result:

( ( 14.95 * 0.6 ) - 8.97 ).abs < 1e-6

(Here, we’ve chosen 1e-6 as our epsilon, which is arbitrary but
probably “small enough” in this case. For mathematically intensive
code, you may need to be more careful.)

Any particular reason against using Float::EPSILON here? :slight_smile:

Maybe Float#== could simply be extended to consider the above? That
would most probably open another can of worms, though, and extending
Float#<=> would open yet another, I guess.

– Shot

I think Float#== as it is is fine. Arguably it could use delta
comparison with Float::EPSILON and leave the exact comparison to eql?
But I’d like it if Float#in_delta(other, delta=Float::EPSILON) was in
core (personally I add it in my libs as Numeric#in_delta).

Regards
Stefan

On Mon, Jun 25, 2007 at 01:52:07AM +0900, Stefan R. wrote:

code, you may need to be more careful.)

Any particular reason against using Float::EPSILON here? :slight_smile:

Comparing floating-point values different from 1.0?

(also, greater errors)

Maybe Float#== could simply be extended to consider the above? That
would most probably open another can of worms, though, and extending
Float#<=> would open yet another, I guess.

– Shot

I think Float#== as it is is fine. Arguably it could use delta
comparison with Float::EPSILON and leave the exact comparison to eql?
But I’d like it if Float#in_delta(other, delta=Float::EPSILON) was in
core (personally I add it in my libs as Numeric#in_delta).

That default value for delta makes no sense in general if you’re using
it as
in the above example.

Comparing the absolute difference against a fixed epsilon (especially
Float::EPSILON) isn’t normally as interesting as giving a bound for the
relative error, so you’d at least need something like

class Float
def in_rdelta(other, rdelta = 1e-6) # or maybe no default at all?
return true if self == other
d = self.abs > other.abs ? (self - other) / self : (self - other) /
other
d.abs <= rdelta
end
end

e = Float::EPSILON # =>
2.22044604925031e-16
1.0.in_rdelta(1.000000000000000222, e) # => true
100.0.in_rdelta(100.000000000000021, e) # => true
100.0.in_rdelta(100.000000000000044, e) # => false
1.0.in_rdelta(1.000000000000000322, e) # => true
1.000000000000000322 == 1.000000000000000222 # => true
“%20.18f” % 1.000000000000000322 # =>
“1.000000000000000222”

And you’d have to add an extra check if you want a different semantics

around 0.0:

0.0.in_rdelta(2.22e-16, 0.1) # => false
0.0.in_rdelta(2e-17, 0.99) # => false
0.0.in_rdelta(2e-20, 0.9999) # => false

On 6/24/07, Mauricio F. [email protected] wrote:

class Float
def in_rdelta(other, rdelta = 1e-6) # or maybe no default at all?

I’d say no default.

If you’re already doing a check for something being in delta of
something else, you might as well specify what you’re looking for.

On 6/25/07, Lloyd L. [email protected] wrote:

I don’t know which Smalltalk he used, but I just tried it in Squeak
and it evalutes to false, just like in Ruby.

7.4

VisualWorks 7.4? (At least that seems to be a smalltalk with a version
number of 7.4).

(You are aware that theres more than one implementation of Smalltalk,
and to
give just a version number is very vague, right?)