35

When multiplying a floating point number that is very close to 1 with an int > 0, can it ever be interpreted as 1.

That is, if Math.random() returns its highest possible result (which is 1 step below 1.0), will

(int)(Math.random() * 8)

be 8 or 7?

For a practical example, can this often-used construct give an index out of bounds error:

someArray[(int)(Math.random() * someArray.length)];

I'm specifically interested in answers for Java and ActionScript 3, but I suppose they all use the same rules for floating point arithmetic, and answers for any platform would be useful.

Update: Though I already accepted an answer, I'd still appreciate confirmation that this can't go wrong in ActionScript 3 either, since a colleague reporting that he saw it go wrong once is what partly prompted me to ask this question.

Bart van Heukelom
  • 43,244
  • 59
  • 186
  • 301
  • I'd be pretty surprised if such a number *never* overflowed into the next int... but I'll wait for a better answer... –  Oct 11 '11 at 09:15
  • 4
    @UdoFholl I didn't intend to use any official mathematical notation, just wanted to indicate a number with many many nines. – Bart van Heukelom Oct 11 '11 at 09:17
  • *When multiplying a floating number that is very close to 1, can it ever be interpreted as 1* -- Yes, if you multiply it by 0 ;-) JK – aioobe Oct 11 '11 at 09:35
  • simply, add IF statement to avoid this situation :) – shox Oct 11 '11 at 13:48
  • 1
    @JoshLee: Mathematically, 0.99999999999999999999999... is the same number as 1.0, but a computer can't represent 0.9999999999999999999999999... in a float or double, which (among other things) makes it impossible for a random number generator to generate it. – cHao Oct 12 '11 at 00:53
  • @cHao I’m talking about the terminating decimal 0.9999999999999999999999. The nearest approximation as a float or double *is* 1.0. – Josh Lee Oct 12 '11 at 12:55
  • 1
    @Josh: Irrelevant, though, since a RNG (being a computer program) won't generate numbers a computer can't represent exactly. – cHao Oct 12 '11 at 14:14

2 Answers2

44

If you multiply the greatest value below 1.0 with someInt (> 0), the result will never be someInt.

This can be exhaustively tested for integers like this:

Double greatestLessThanOne = Double.longBitsToDouble(4607182418800017407L);

// Assert that greatestLessThanOne is indeed the largest double less than 1.
//assert 1.0 == greatestLessThanOne + Math.ulp(greatestLessThanOne);

for (int i = 1; i >= 0; i++)
    if ((int) (greatestLessThanOne * i) == i)
        System.out.println("Exception found: " + i);

The snippet produces no output.

(Math.ulp returns the distance between the given double and the double value next larger in magnitude. The assertion thus ensures that greatestLessThanOne is indeed the greatest value less than 1.0.)

In other words, your line

Object element = elementArray[(int)(Math.random() * elementArray.length)];

will never give rise to an ArrayIndexOutOfBoundsException.


Furthermore, according to Mark Dickinsons comment over here, this holds also when multiplying with a double.

With IEEE 754 floating-point arithmetic in round-to-nearest mode, you can show that x * y < y for any x < 1.0 and any non-tiny positive y. (It can fail if y is either subnormal or the smallest positive normal number.)

Community
  • 1
  • 1
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • 2
    Good answer. And [Java](http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html) uses round-to-nearest: "The Java programming language requires that floating-point arithmetic behave as if every floating-point operator rounded its floating-point result to the result precision. Inexact results must be rounded to the representable value nearest to the infinitely precise result; if the two nearest representable values are equally near, the one with its least significant bit zero is chosen. This is the IEEE 754 standard's default rounding mode known as **round to nearest**." – Mike Samuel Oct 11 '11 at 09:26
  • Accepted this answer since most platforms will follow IEEE 754. Still, do you happen to know if ActionScript 3 / Flash does so as well? I heard rumours that it can actually go wrong there. – Bart van Heukelom Oct 11 '11 at 11:06
  • It's the same for ActionScript. [Specs](http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f88.html) says it should use the IEEE format (and round-to-nearest is the default rounding mode.) – aioobe Oct 11 '11 at 11:24
-2

Just round it, may be like this :

BigDecimal bd = new BigDecimal(Double.toString(d));
bd = bd.setScale(decimalPlace,BigDecimal.ROUND_HALF_UP);
Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
hendra ong
  • 21
  • 1