2

I have a library that modifies an input (adding or multiplying the input with one or more stored variables). These variables are stored as floats. Usually, the input is also a float, but in some cases it's an int. I'm concerned about the accuracy of this.

float GetValue(float input)
{
    foreach (float modifier in various_data_sources)
    {
        if (isFactor)
            input = input * modifier;
        else
            input = input + modifier;
    }
    return input;
}

void MainLogic()
{
    int defaultValue = 3;
    // If the modifier is 2 (add), I expect the final modified int to be 5:
    DoSomeIntThing((int) GetValue(defaultValue));
}

Is there anything I can do to make this safer? The value modifications need to be dynamic, and separating the modifications to integer operations and floating point operations will be a mess. Is this as unsafe as I think it is, or will an operation like (int)(2.0f+(float)3) always yield the hoped-for result?

piojo
  • 6,351
  • 1
  • 26
  • 36
  • What do you expect on an input of `3.5`? – Elliott Frisch Dec 03 '13 at 06:29
  • 4
    Related [Which is the first integer that an IEEE 754 float is incapable of representing exactly?](http://stackoverflow.com/questions/3793838/which-is-the-first-integer-that-an-ieee-754-float-is-incapable-of-representing-e) – Martin Smith Dec 03 '13 at 06:30
  • Can `various_data_sources` not be modified to store `int` for int operations? Then you could just use overloading. – Aron Dec 03 '13 at 06:30
  • @MartinSmith I think your link could be quite easily expanded to a full answer (of No its not safe, for `int`s bigger than those numbers). – Aron Dec 03 '13 at 06:34
  • @MartinSmith, thanks! I didn't realize so many integers were represented exactly in floating point. My concern should be a non-issue, then. If you post that link as an answer, I can accept it. (I didn't mention that the numbers I'm dealing with are all small, so it's safe.) – piojo Dec 03 '13 at 06:34
  • @piojo I suggest you switch to using `double` just to be on the safe side. – Aron Dec 03 '13 at 06:44
  • @Aron, thanks, but it's game development (not mission critical), and I have a pretty good understanding of the range of the input values and modifiers. Also, if it's gonna fail, I'd rather it fail sooner than later. – piojo Dec 03 '13 at 08:12
  • If the numbers are small as you say, why use float at all? You could do all the math using fixed point decimals (for example, if you want two decimal places of precision, you would just multiply the value by `100`). Of course, it's possible it would be slower (for multiplication, you have to do `(a * b) / 100`), but that's what profiling is for. And of course, convenience is very high valued, even in games - if the performance hit isn't significant enough, just go for what's safe and easy. – Luaan Jan 13 '14 at 08:56
  • @Luaan, there are lots of situations that can't (or shouldn't) distinguish between ints and floats. Some involve serialization (XML/JSON). Another example is a UI that lets a user to type a float or an integer (and corresponding backend logic that's equally valid for a float or integer). My current use case is both. In fact, it's a game dev tool, so "add 1 life" and "add 1.5 meters" should both be error free, valid sentences. – piojo Jan 21 '14 at 07:37
  • 1
    Yeah, that's where it gets complicated. The JSON float is decimal, so it can actually say "1.5" and it means the same "1.5" you do. When saving, this is easy to achieve (float.ToString("f3") will ensure mostly correct rounding). When you load the value, you're converting it to base-2 "decimal" value => loss of precision. Many games actually use integers to do fixed point decimal math (for example, the Europa Universalis series uses integers with 3 decimal places). So you parse the input ("1" => 1000, "1.5" => 1500), and it will keep the decimal precison up to 3 decimal places. – Luaan Jan 21 '14 at 10:05
  • @Luaan Thanks, that was enlightening. I will just leave it the same for now, as it seems good enough and unlikely to cause bugs. Next time, I'll think about whether I need the "multiply by 10000" trick. – piojo Jan 30 '14 at 05:25

1 Answers1

1

Until your numbers are integer and have not more digits that a float mantissa can have, float operations on them are precise. The errors in counting floats appear because of cutting the ends. And while it doesn't happen it is nothing to be afraid of. But the first division by something different from a power of 2 will break this paradise. Or any operation that makes the result too long.

Gangnus
  • 24,044
  • 16
  • 90
  • 149