3

Using C++, I'm trying to cast a float value to an int using these instructions :

#include <iostream>

int main() {
    float NbrToCast = 1.8f;
    int TmpNbr = NbrToCast * 10;
    std::cout << TmpNbr << "\n";
}

I understand the value 1.8 cannot be precisely represented as a float and is actually stored as 1.79999995.

Thus, I would expect that multiplying this value by ten, would result to 17.99999995 and then casting it to an int would give 17.

When compiling and running this code with MinGW (v4.9.2 32bits) on Windows 7, I get the expected result (17).

When compiling and running this code with CLang (v600.0.57) on my Mac (OS X 10.11), I get 18as a result, which is not what I was expecting but which seems more correct in a mathematical way !

Why do I get this difference ?

Is there a way to have a consistent behavior no matter the OS or the compiler ?

Green goblin
  • 9,898
  • 13
  • 71
  • 100
Jérôme
  • 26,567
  • 29
  • 98
  • 120
  • 2
    see https://stackoverflow.com/questions/18494237/floating-point-mismatch-between-compilers-visual-studio-2010-and-gcc – v7d8dpo4 Apr 27 '16 at 08:49
  • Try changing the last line to `std::cout << std::precision(20) << TmpNbr << "\n";` – Richard Critten Apr 27 '16 at 08:51
  • @RichardCritten: `TmpNbr` is `int`, then what is the point of `std::precision(20)`? – Nawaz Apr 27 '16 at 08:53
  • There are a number of IEEE-754 [rounding rules](https://en.wikipedia.org/wiki/IEEE_floating_point#Rounding_rules); it's possible the default each compiler is using is different. Try setting the rounding mode (http://en.cppreference.com/w/cpp/numeric/fenv/FE_round) and see what happens? – Yuushi Apr 27 '16 at 08:58
  • @Nawaz sorry I was having a stupid moment. – Richard Critten Apr 27 '16 at 08:59
  • With floating point, there's rarely a way to get completely consistent behaviour between platforms. – molbdnilo Apr 27 '16 at 09:07
  • 1
    @Yuushi Much more likely than a difference in rounding mode is a difference in value for `FLT_EVAL_METHOD`. – Pascal Cuoq Apr 27 '16 at 09:09
  • My first assumption is that it is a compiler optimization. I suggest CLang computes the result at compile time. Would be interesting to know, what the output would be if TmpNbr would be a float also. – exilit Apr 27 '16 at 10:34

1 Answers1

-1

Like Yuushi said in the comments, I guess the rounding rules may differ for each compiler. Having a portable solution on such a topic probably means you need to write your own rounding method.

So in your case you probably need to check the value of the digit after 7 and increment the value or not. Let's say something like:

int main() {
    float NbrToCast = 1.8f;
    float TmpNbr = NbrToCast * 10;
    std::cout << RoundingFloatToInt(TmpNbr) << "\n";
}

int RoundingFloatToInt(const float &val)
{
  float intPart, fractPart;
  fractpart = modf (val, &intpart);
  int result = intPart;
  if (fractpart > 0.5) 
  {
    result++;
  }
  return result;
}

(code not tested at all but you have the idea)

If you need performance, it's probably not great but I think it should be portable.

Mikitori
  • 589
  • 9
  • 21