Microrant on Ruy's Math Skills

On Mon, Jan 23, 2012 at 11:40 AM, Robert K.
[email protected]wrote:

amount = BigDecimal.new(“15.5”)
15.5D

is better naming (maps to “Decimal” and the %d of format string).

Or

amount = 15.4.to_bd
amount = 15.4.to_decimal
amount = 15.4.to_dec
amount = BD(15.4)

When writing 15.4 … and then calling a method on it,
it’s already too late.

BD(“15.4”) would work though …

1.9.3p0 :001 > def BD(number)
1.9.3p0 :002?> BigDecimal.new(number)
1.9.3p0 :003?> end
=> nil
1.9.3p0 :004 > def BD_from_string(string)
1.9.3p0 :005?> BigDecimal.new(string)
1.9.3p0 :006?> end
=> nil
1.9.3p0 :007 > BD(15.4)
NameError: uninitialized constant BigDecimal
from (irb):2:in BD' from (irb):7 from /home/peterv/.rvm/rubies/ruby-1.9.3-p0/bin/irb:16:in
1.9.3p0 :008 > require ‘bigdecimal’
=> true
1.9.3p0 :009 > BD(15.4)
ArgumentError: can’t omit precision for a Rational.
from (irb):2:in new' from (irb):2:in BD’
from (irb):9
from /home/peterv/.rvm/rubies/ruby-1.9.3-p0/bin/irb:16:in `’
1.9.3p0 :010 > BD_from_string(“15.4”)
=> #BigDecimal:96787bc,‘0.154E2’,18(18)

Peter

On Mon, Jan 23, 2012 at 11:40 AM, Robert K.
[email protected]wrote:

amount = BigDecimal.new(“15.5”)
15.5D

is better naming (maps to “Decimal” and the %d of format string).

Or

amount = 15.4.to_bd

Thanks for the idea.

I fixed my feature request with this code in
a library file:

require ‘bigdecimal’
class ::String
def to_bd
BigDecimal.new(self)
end
end

So it only works on strings (that’s what I want).

Now I can say:

describe “balance setter and getter” do
subject.balance = “15.4”.to_bd
subject.balance.should == “15.4”.to_bd
end

Thanks again,

Peter

On Mon, Jan 23, 2012 at 08:38:56PM +0900, Peter V. wrote:

end

end

So it only works on strings (that’s what I want).

Now I can say:

describe “balance setter and getter” do
subject.balance = “15.4”.to_bd
subject.balance.should == “15.4”.to_bd
end

Is there any reason this would not be better done with symbols than with
strings?

On Mon, Jan 23, 2012 at 11:51 AM, Peter V.
[email protected] wrote:

Based on this discussion, it would actually be useful to me if I could

amount = 15.4.to_dec
amount = BD(15.4)

When writing 15.4 … and then calling a method on it,
it’s already too late.

BD(“15.4”) would work though …

Darn, right you and Josh are. Well, then these methods should also be
defined on String.

Kind regards

robert

On Mon, Jan 23, 2012 at 07:33:20PM +0900, Peter V. wrote:

amount = 15.5B

Then we could also answer future questions about

“How come 1.1 - 1.0 != 0.1 ??”

with

“1.1B - 1B == 0.1B”

Even that and the ‘1.1’.to_dec option mentioned elsewhere seem pretty
cumbersome when working with a lot of numbers. How difficult would it
be
to change the way Ruby parses 1.1 within a given program so it just
automatically uses BigDecimal rather than Float? That way, one could
just tell Ruby to use BigDecimal instead of Float by default at the top
of the program file and go forward confident that Float errors will not
creep into the program (unless using a library that explicitly uses
floating point numbers within itself).

On Mon, Jan 23, 2012 at 6:38 PM, Chad P. [email protected] wrote:

  BigDecimal.new(self)

end

Is there any reason this would not be better done with symbols than with
strings?

For an initial test without format checking or accessing
the database the exact type that is saved is indeed not
relevant, so a symbol would be a good idea to reduce
GC effort (thanks).

But, in this test, I really needed to actually save to
the database (and that “balance” column is obviously
in “decimal” format). So at that time it would need to be
in the exact format.

The reason I needed a “real” save is that I have delegated
this “balance” to a different model and I had forgotten the
:autosave option on the association, which made the
save of the associated model fail in the condition that the
current model was not changed? The actual test code is
more complex and involves saving, and finding the record
back from the database and then checking for the value.

But I see your point, for simpler test cases a symbol would
be a nice and more efficient way to test this.

Peter

Even that and the ‘1.1’.to_dec option mentioned elsewhere seem pretty
cumbersome when working with a lot of numbers. How difficult would it be
to change the way Ruby parses 1.1 within a given program so it just
automatically uses BigDecimal rather than Float? That way, one could
just tell Ruby to use BigDecimal instead of Float by default at the top
of the program file and go forward confident that Float errors will not
creep into the program (unless using a library that explicitly uses
floating point numbers within itself).

Parse time is different than execution time.

No, it’s not a terminology difference. That’s why it won’t work. You
can’t have some code execute to change how the parser works. Parse
time happens before execution time.

On Tue, Jan 24, 2012 at 03:14:27AM +0900, Steve K. wrote:

FWIW, ruby-core member Kenta M. has a proposal to replace Float with
BigDecimal. Here are his slides from rubyconf on the subject:

Sorry if this has been mentioned already.

pete

On Mon, Jan 23, 2012 at 2:47 PM, Pete H. [email protected]
wrote:

FWIW, ruby-core member Kenta M. has a proposal to replace Float with
BigDecimal. Here are his slides from rubyconf on the subject:

Float is Legacy

This is very encouraging. I haven’t been able to find the time, but
maybe
introducing dual fix point might be viable?
google for LNCS 3203 - Dual Fixed-Point: An Efficient Alternative to
Floating
A pdf of that article should be available.

Andrew McElroy

Sorry if this has been mentioned already.

On Tue, Jan 24, 2012 at 05:45:18AM +0900, Steve K. wrote:

No, it’s not a terminology difference. That’s why it won’t work. You
can’t have some code execute to change how the parser works. Parse
time happens before execution time.

Ruby is pretty dynamic. It seems entirely reasonable to consider
whether
Float could be redefined to dispatch to BigDecimal except when called
explicitly, for instance.

On Tue, Jan 24, 2012 at 10:19 AM, Ryan D. [email protected]
wrote:

Ruby is pretty dynamic. It seems entirely reasonable to consider whether
Float could be redefined to dispatch to BigDecimal except when called
explicitly, for instance.

Except for that whole “parse time is different from run time” part you
seem to be blithely ignoring. If you’ve already parsed float literals, then
they’re floats and are already lossy.

Unless the parser stores a string representation in addition to the
float itself. Then at runtime, the string rep could be used to
instantiate a BigDecimal if that runtime option has been activated.

Of course, I’m NOT advocating this!

On Jan 23, 2012, at 15:13 , Chad P. wrote:

On Tue, Jan 24, 2012 at 05:45:18AM +0900, Steve K. wrote:

No, it’s not a terminology difference. That’s why it won’t work. You
can’t have some code execute to change how the parser works. Parse
time happens before execution time.

Ruby is pretty dynamic. It seems entirely reasonable to consider whether
Float could be redefined to dispatch to BigDecimal except when called
explicitly, for instance.

Except for that whole “parse time is different from run time” part you
seem to be blithely ignoring. If you’ve already parsed float literals,
then they’re floats and are already lossy.

On Tue, Jan 24, 2012 at 08:19:06AM +0900, Ryan D. wrote:

Except for that whole “parse time is different from run time” part you
seem to be blithely ignoring. If you’ve already parsed float literals,
then they’re floats and are already lossy.

Are you telling me that 1.1 is automatically lossy, regardless of how
you
got there? I guess I need to go back and refresh my understanding of
the
math, because I thought a literal decimal number was fine but one
achieved by arithmetic was likely to contain subtle errors due to the
way
the binary math is handled.

On Jan 23, 2012, at 16:57 , Chad P. wrote:

the binary math is handled.
It’d be nice if you read the thread before chipping in. Adam P.
nailed this one. Here’s another example:

% ruby -e ‘puts “%.60f” % 1.1’
1.100000000000000088817841970012523233890533447265625000000000

On Tue, Jan 24, 2012 at 10:23:36AM +0900, Ryan D. wrote:

It’d be nice if you read the thread before chipping in. Adam P.
nailed this one. Here’s another example:

I don’t get it. I’ve been polite and reasonable – and evidently
overlooked one fucking statement. For this crime, I’ve got a couple
people crawling up my ass with pitchforks and torches.

Have fun. You don’t need my involvement to “justify” your prickish
behavior any longer.

On Tue, Jan 24, 2012 at 1:57 AM, Chad P. [email protected] wrote:

On Tue, Jan 24, 2012 at 08:19:06AM +0900, Ryan D. wrote:

Except for that whole “parse time is different from run time” part you
seem to be blithely ignoring. If you’ve already parsed float literals,
then they’re floats and are already lossy.

Are you telling me that 1.1 is automatically lossy, regardless of how you
got there?

1.1 is a decimal floating point literal. This is translated into a
floating point number at some point in time (likely parse time). From
there on there is only a floating point number which has a binary
representation. Since certain decimal values cannot be exactly
represented as binary numbers there is loss the very moment the
translation occurs.

I guess I need to go back and refresh my understanding of the
math, because I thought a literal decimal number was fine but one
achieved by arithmetic was likely to contain subtle errors due to the way
the binary math is handled.

There is imprecision in the translation and further numeric effects
which affect precision later. The resulting imprecision (compared to
what pure math or symbolic calculations would yield) depends on

  • translation of decimal literals to binary representation
  • limits of the binary representation
  • nature of the operations
  • order of the operations
  • translation back to decimal representation

Given all this it’s rather surprising that output results are so close
to what one would expect. :slight_smile: You can study the details at

and for example for one format:

Kind regards

robert

Different sections to a forum make great sense as well.

Maybe there already is a vibrant one out there that I don’t know about.

As someone who cares for a local ruby forum, I can say one thing out
of experience: Forums are on a decline, so I wouldn’t bother about
creating
a new one, even if it was a more fitting environment.

As for the discussion: this comes up every 6 months and the horse is
already
dead in the first mail. While I can certainly understand the frustration
with
float, the decision is made. Reverting it would mean touching every
piece of
software that does statistics. And in contrast to popular belief, there
is
quite a lot of it out there. I know that at least 10 of my reporting
scripts
running at several clients offices would break, which would be
unacceptable for
me (expecially, because float is the correct datatype there).
Changing such a primitive in a language is reckless.

I am perfectly fine with [insert the next big thing] taking a different
approach there.

Regards,
Florian

It’d be nice if you read the thread before chipping in. Adam P.
nailed this one. Here’s another example:

I don’t get it. I’ve been polite and reasonable – and evidently
overlooked one fucking statement. For this crime, I’ve got a couple
people crawling up my ass with pitchforks and torches.

Have fun. You don’t need my involvement to “justify” your prickish
behavior any longer.

I think it’s come to the point where a forum is better than a mailing
list for general discussions about Ruby. I never would have said that
a few years ago, but I’m saying it now. In a mailing list, every
message gets beamed into your inbox, so some people think they have
the right to react negatively to ignorance/oversights/off-topic
chatter, etc. In a forum, you opt in to discussions, and have to
accept that it’s a discussion, which typically involves repetition and
redundancy, as it’s conducted by humans.

Different sections to a forum make great sense as well.

Maybe there already is a vibrant one out there that I don’t know about.