if I understand well, the value of a float might be truncated if it is stored in RAM, and might not be truncated if it is not (might = it depend on my system, hardware, compiler, etc).
In my example (write 1), since I used intermediate steps, some values got stored in RAM and got truncated, hence the loss of precision. In my other example (write 2), since I have no intermediate steps, nothing went into RAM, and nothing got truncated.
Finally, if I understand well the article, there no way of predicting this (the best thing is to avoid RAM usage)?
P.S. Militie, yes, it was written exactly that way ;)
> In my example (write 1), since I used intermediate steps,
> some values got stored in RAM and got truncated, hence the loss of precision.
In the earlier example, there was a narrowing conversion from double to float, followed by a widening conversion from the resultant float back to double. The narrowing conversion could have resulted in loss of precision.
If instead, we had written
1 2 3 4 5 6
float a = 1.0;
int b = 3;
floatdouble c = a/b;
floatdouble d = (c * b) - 1.0;
cout << d << endl;
There would have been no narrowing conversion; the result may have been different.
#include <iostream>
#include <iomanip>
void print_type(float) { std::cout << "float\n" ; }
void print_type(double) { std::cout << "double\n" ; }
int main()
{
std::cout << "type of 1.0 is: " ;
print_type(1.0) ; // type of literal 1.0 is 'double'
float a = 1.0;
int b = 3 ;
// 'usual arithmetic conversions' are applied
// 1. If either operand is of type long double, the other operand is converted to type long double.
// 2. If the above condition is not met and either operand is of type double, the other operand is converted to type double.
// https://msdn.microsoft.com/en-us/library/3t4w2bkb.aspx
// type of a/b - 1.0 is 'double'
auto result = a/b * b - 1.0 ; // type of result is 'double'
std::cout << "type of result is: " ;
print_type(result) ; // double
std::cout << std::fixed << std::setprecision(20) << result << '\n' ; // pint the value of the double
float c = a / b ; // type of c is 'float'
float d = (c*b) - 1.0 ; // type of d is 'float' ; result of (c*b) - 1.0 (double) is 'narrowed' to a float;
// there may be a loss of precision during the narrowing
// calls std::ostream::operator<< (float)
// which calls std::num_put<char>::put(double) => std::num_put<char>::do_put(double)
// float d is widened to a double; the result of this widening may not be precisely equal
// to the value pf result due to possible loss of precision during the earlier narrowing
std::cout << d << '\n' ; // print the result of c widened to double
float c1 = a / b ;
double d1 = (c1*b) - 1.0 ;
std::cout << d1 << '\n' ; // the result printed may be different from that printed for float d
double c2 = a / b ;
double d2 = (c2*b) - 1.0 ;
std::cout << d2 << '\n' ; // the result printed may be different from that printed for double d1
}