1

Situation

I am in a situation where I will have a lot of numbers around about 0 - 15. The vast majority are whole numbers, but very few will have decimal values. All of the ones with decimal value will be "#.5", so 1.5, 2.5, 3.5, etc. but never 1.1, 3.67, etc.

I'm torn between using float and int (with the value multiplied by 2 so the decimal is gone) to store these numbers.

Question

Because every value will be .5, can I safely use float without worrying about the wierdness that comes along with floating point numbers? Or do I need to use int? If I do use int, can every smallish number be divided by 2 to safely give the absolute correct float?

Is there a better way I am missing?

Other info

I'm not considering double because I don't need that kind of precision or range.

I'm storing these in a wrapper class, if I go with int whenever I need to get the value I am going to be returning the int cast as a float divided by 2.

What I went with in the end

float seems to be the way to go.

Community
  • 1
  • 1
Captain Man
  • 6,997
  • 6
  • 48
  • 74
  • Some reading: http://floating-point-gui.de/ –  Sep 11 '15 at 15:12
  • So what are your primary concerns? If this is an internal implementation detail, I doubt that it'll matter much. What data are you initializing this from? – Jon Skeet Sep 11 '15 at 15:14

3 Answers3

2

This is not a theoretical proof but you can test it empirically:

public static void main(String[] args) {
  BigDecimal half = new BigDecimal("0.5");
  for (int i = 0; i < Integer.MAX_VALUE; i++) {
    float f = i + 0.5f;
    if (new BigDecimal(f).compareTo(new BigDecimal(i).add(half)) != 0) {
      System.out.println(new BigDecimal(i).add(half) + " => " + new BigDecimal(f));
      break;
    }
  }
}

prints:

8388608.5 => 8388608

Meaning that all xxx.5 can be exactly represented as a float between 0.5 and 8388607.5.

For larger numbers float's precision is not enough to represent the number and it is rounded to something else.

assylias
  • 321,522
  • 82
  • 660
  • 783
  • whereas the `int` solution can represent every half int value between -1073741824 to 1073741823.5 – phuclv Sep 11 '15 at 16:19
2

Let's refer to the subset of floating point numbers which have a decimal portion of .0 or .5 as point-five floats, or PFFs.

The following properties are guaranteed:

  • Any number up to 8 million or so (2^23, to be exact) which ends in .0 or .5 is representable as a PFF.
  • Adding/subtracting two PFFs results in a PFF, unless there's overflow.
  • Multiplying a PFF by an integer results in a PFF, unless there's overflow.

These properties are guaranteed by the IEEE-754 rules, which give a 24-bit mantissa and guarantee exact rounding of exact results.

Using ints will give you a somewhat larger range.

Sneftel
  • 40,271
  • 12
  • 71
  • 104
0

There will be no accuracy issues with .5's with float for that range, so both approaches will work.

If these represent actual number values, I would chose the float simply because it consumes the same amount of memory and I don't need to write code to convert between some internal int representation and the exposed float value.

If these numbers represent something other than a value, e.g. a grade from a very limited set, I would consider modelling them as an enum, depending on how these are ultimately used.

Durandal
  • 19,919
  • 4
  • 36
  • 70