0

Are these two C# methods completely deterministic - as in they produce same result across all platforms?

Fix64 is struct that has rawValue field of type long. ONE is a constant defined like this const long ONE = 1L << 32;

Function 1:

public static explicit operator Fix64(double value) {
            return new Fix64((long)(value * ONE));
        }

Fix64 constructor that takes in a long value just assigns it to rawValue field. Operation in question here is the multiplication. ONE is going to be converted to double. Then two double values are going to be multiplied. This can happen at higher precision according to C# specifications. Result is then truncated by long cast. Is there any chance for the least significant bit of the resulting long value to be different, if different precision are used for multiplication on different platforms? Or is this method completely deterministic?

Function 2:

public static explicit operator double(Fix64 value) {
        return (double)value.rawValue / ONE;
    }

This is similar to 1st example. Just that here we have division operation between doubles and that we return result as a double. Is it possible that if we compare result of this method with another double, compiler can leave resulting double in higher precision during that comparison?

Would another cast ensure that this comparison will always be deterministic?

(double)((double)value.rawValue / ONE)

EDIT: These two functions convert between FixedPoint64 type and double type. The argument here is that by doing only single operation we are not using extended intermediate floating point value for additional operation. Thus by immediately truncating result to standard precision, calculation is supposed to be deterministic. Or are there any flaws in that logic?

zigzag
  • 579
  • 5
  • 17
  • Possible duplicate of [Is floating-point math consistent in C#? Can it be?](http://stackoverflow.com/questions/6683059/is-floating-point-math-consistent-in-c-can-it-be) – Sinatr Sep 07 '16 at 09:27
  • Surely you already know the answer. The basic mistake you are making is assuming that it has something to do with the expression you used. That is not correct, you cannot assume that the *value* argument is consistent. – Hans Passant Sep 07 '16 at 09:36
  • @HansPassant I don't understand what you mean. Is answer no for both functions? I need to convert double values to Fix64 struct and back to double values multiple times. I need to know if these conversions will produce same results on different platforms or do they need to be fixed. I have read arguments that determinism issues arise only in intermediate results across multiple operations due to FPU extended precision, and possibly in implementations of transcendental functions, but not for single calculation that is immediately truncated like in the first function. – zigzag Sep 07 '16 at 10:24
  • It affects *all* floating point operations. Including whatever expression produced the *value* argument. The code in the snippet you posted does not make it more or less inconsistent. Just keep the basic guidance in mind, a *double* can never store more than 15 accurate digits. And computation *is* consistent for the exact same *compiled* program running on the exact same operating system flavor. – Hans Passant Sep 07 '16 at 10:37
  • If you are referring to double value argument passed into the first function, that value will be either read from disk (which should be consistent across all platforms) or a product from function 2, that is stored in a double field. That stored double value will not be modified (only compared to). For all calculations, it will be first converted to fixed point Fix64 struct, modified as fixed point number, and then converted back again to double using function 2. Question is, does any of these two functions need to be fixed? – zigzag Sep 07 '16 at 10:59
  • @Sinatr I have edited the question trying to explain why may these two specific cases be different from general C# floating point determinism discussion. That specific thread doesn't even go into details where exactly can FP differences between platforms occur. – zigzag Sep 07 '16 at 11:12

1 Answers1

0

The answer is yes, both are deterministic. Explanation I got about this is from the author of the library is:

For multiplication/division, if one of the FP numbers is power of two number (2^x), significant/mantissa won't change during calculation. Only exponent will change (point will move). So rounding will never happen. Result will be deterministic.

Example: A number like 2^32 is represented as (exponent: 32, mantissa: 1). If we multiply this with another float (exp, man), the result is (exp + 32, man * 1). For division, the result is (expo - 32, man * 1). Multiplying the mantissa by 1 doesn't change the mantissa, so it doesn't matter how many bits it has.

zigzag
  • 579
  • 5
  • 17