﻿ To_D to Always Return 2 Decimals Places in Ruby - ITCodar

# To_D to Always Return 2 Decimals Places in Ruby

## Displaying an output in Ruby to 2 decimal places

You have to add a dot in the format to say you want the `2` to be the precision after the decimal dot:

``s = '%.2f' % @price``

## How do you round a float to 2 decimal places in JRuby?

Float#round can take a parameter in Ruby 1.9, not in Ruby 1.8. JRuby defaults to 1.8, but it is capable of running in 1.9 mode.

## How can I make eval return a number with decimal places?

All you need is the denominator of the division to be floating point and Ruby will understand to use floating point arithmetic on the expression instead of the default integer arithmetic:

``irb(main):001:0> a = 5irb(main):002:0> b = 4irb(main):003:0> a / b=> 1irb(main):004:0> a / b.to_f=> 1.25irb(main):005:0> (a + b) / b.to_f=> 2.25``

Edit

To further clarify - It actually has nothing to do with `eval` in itself. It's just the way Ruby (and most other languages) handle arithmetic expressions. Most expressions are done with integer arithmetic by default.

When doing division in Ruby all you need is either dividend or divisor to be float to trigger floating point arithmetic.

## rails decimal scale = 2 not working

`scale` specifies number of digits after the decimal point preserved in the database. Saving `1.234` will round to `1.23`, `500.00` will be stored as `500.00`.

In Ruby on Rails, they will be represented as a `BigDecimal`. The `BigDecimal` will not know about the format that was used in the DB. If its value is `500.0`, its `to_s` method will output it as `500.0` because that's accurate enough.

To format the values as currency, use the `number_to_currency` helper method.

Also see Ruby on Rails: best method of handling currency / money and Does Ruby have any number formatting classes?

## Inconsistent conversion of Float into Decimal in Ruby

So why is this happening?

TL;DR different precisions are used.

`64.4.to_d` calls `bigdecimal/util`'s `Float#to_d`:

``def to_d(precision=nil)  BigDecimal(self, precision || Float::DIG)end``

Unless specified, it uses an implicit precision of `Float::DIG` which is `15` for current implementations:

``Float::DIG#=> 15``

So `64.4.to_d` is equivalent to:

``BigDecimal(64.4, Float::DIG)#=> #<BigDecimal:7fd7cc0aa838,'0.644E2',18(36)>``

`BigDecimal#*` on the other hand converts a given float argument via:

``if (RB_TYPE_P(r, T_FLOAT)) {    b = GetVpValueWithPrec(r, DBL_DIG+1, 1);}``

`DBL_DIG` is the C-equivalent of `Float::DIG`, so it's basically:

``BigDecimal(64.4, Float::DIG + 1)#=> #<BigDecimal:7fd7cc098408,'0.6440000000 000001E2',27(36)>``

That said, you can get the expected result if you provide the precision explicitly, either:

``f.to_d(16) == 1.to_d * f#=> true``

or:

``f.to_d == 1.to_d.mult(f, 15)#=> true``

and of course by explicitly converting `f` via `to_d`:

``f.to_d == 1.to_d * f.to_d#=> true``

Isn't this a bug?

It looks like one, you should file a bug report.

Note that neither `0.644E2`, nor `0.6440000000000001E2` is an exact representation of the given floating point number. As already noted by Eli Sadoff, `64.4`'s exact value is `64.400000000000005684341886080801486968994140625`, so the most exact `BigDecimal` representation would be:

``BigDecimal('64.400000000000005684341886080801486968994140625')#=> #<BigDecimal:7fd7cc04a0c8,'0.6440000000 0000005684 3418860808 0148696899 4140625E2',54(63)>``

IMO, `64.4.to_d` should return just that.