1

As far as I know int64 can be converted in float64 in Go, the language allows this with float64(some_int64_variable), but I also know that not all 64 bit signed integers can be represented in double (because of IEE754 approximations).

We have some code which receives the price of an item in cents using int64 and does something like

const TB                    = 1 << 40

func ComputeSomething(numBytes int64) {
    Terabytes := float64(numBytes) / float64(TB)

I'm wondering how safe this is, since not all integers can be represented with doubles.

Dean
  • 6,610
  • 6
  • 40
  • 90
  • 2
    How many items are you dealing with which cost more than 20 million dollars? If the answer is zero (I suspect it is for most domains) you could easily fit the cost in cents in an `int32` rather than an `int64`. So are you really worried about prices that *require the full precision of an `int64`*? – Damien_The_Unbeliever Mar 12 '21 at 15:53

2 Answers2

6

Depends on what you mean by "safe".

Yes, precision can be lost here in some cases. float64 cannot represent all values of int64 precisely (since it only has 53 bits of mantissa). So if you need a completely accurate result, this function is not "safe"; if you want to represent money in float64 you may get into trouble.

On the other hand, do you really need the number of terabytes with absolute precision? Will numBytes actually divide by TB accurately? That's pretty unlikely, but it all depends on your specification and needs. If your code has a counter of bytes and you want to display approximately how many TB it is (e.g. 0.05 TB or 2.124 TB) then this calculation is fine.

Eli Bendersky
  • 263,248
  • 89
  • 350
  • 412
5

Answering "is it safe" really requires a better understanding of your needs, and what exactly you do with these numbers. So let's ask a related but more precise question that we can answer with certainty:

What is the minimum positive integer value that float64 cannot exactly represent?

For int64, this number turns out to be 9007199254740993. This is the first integer that float64 "skips" over.

This might look quite large, and perhaps not so alarming. (If these are "cents", then I believe it's about 90 trillion dollars or so.) But if you use a single-precision float, the answer might surprise you. If you use float32, that number is: 16777217. about 168 thousand dollars, if interpreted as cents. Good thing you're not using single-precision floats!

As a rule of thumb, you should never use float types (whatever precision it might be) for dealing with money. Floats are really not designed for "money" like discrete quantities, but rather dealing with fractional values that arise in scientific applications. Rounding errors can creep up, throwing off your calculations. Use big-integer representations instead. Big integer implementations might be slower since they are mostly realized in software, but if you're dealing with money computations, I'd hazard a guess that you don't really need the speed of floating-point computation that the hardware can provide.

alias
  • 28,120
  • 2
  • 23
  • 40