0

I have a list of float numbers, representing currency, and I need to turn them into integers, for precision.

The task is to turn float numbers into integers, likes:

  • 0.95 => 95
  • 1 => 100
  • 1,465.01 => 146501

The problem is:

  1. I don't have access to change the input csv files
  2. The numbers came in a variety of ways (1.00, 1.0, 1, .95, 0.95, etc)

How can, safely, I turn these numbers into integers?

Some examples of my problem:

  • ('16.81'.to_f * 100).to_i => 1680
  • ('16.81'.to_f * 100_00).to_i / 100 => 1681
  • ('342.28'.to_f * 100).to_i => 34228
  • ('342.28'.to_f * 100_00).to_i / 100 => 34227

__ EDIT __

By the way, I'm using ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin19]

Nicos Karalis
  • 3,724
  • 4
  • 33
  • 62

2 Answers2

2

Floating point numbers can't necessarily represent all decimal numbers. This is explained in Is floating point math broken?. As such, when dealing with floats, you are always a bit uncertain and usually need to use rounding to get a desired number.

From your examples, ('16.81'.to_f * 100) results in 1680.9999999999998. Getting the integer value from that cuts off the fractional part, resulting in 1680. By using round instead, you can get the desired integer (which also solves the issue of partial cents). When relying on this, please note the details of how Ruby rounds exactly, specifically the optional half argument).

Instead of relying on Floats however, a better idea is to use BigDecimal numbers instead which allow arbitrary precision floating point numbers.

require 'bigdecimal'

(BigDecimal('16.81') * 100).round
# => 1681

(BigDecimal('.95') * 100).round
# => 95

number = '1,465.01'
# remove any "additional" characters
normalized = number.gsub(/[^-+0-9.]/, '')
(BigDecimal(normalized) * 100).round
# => 146501

In the last example, I have shown how you might cleanup your "human-readable" numbers for consistent parsing. Depending on your source data, you might need to perform additional changes (e.g. if you might have values such as '1.465,01' as is common in e.g. some European countries).

Holger Just
  • 52,918
  • 14
  • 115
  • 123
1

Use Bigdecimal for float numbers and append .to_i to convert it in integer

require 'bigdecimal'
(BigDecimal('16.81') * 100).to_i  # 1681
(BigDecimal('342.28') * 100).to_i # 34228

For more details you can refer https://corainchicago.github.io/blog/why-does-ruby-add-numbers-wrong/

Chakreshwar Sharma
  • 2,571
  • 1
  • 11
  • 35