8

Consider:

double f = foo();
double g = -f;

where foo() can return anything that be assigned to f.

is double g = -f; safe in C and C++? For IEEE 754 types it obviously is but C and C++ do not restrict floating point implementation to that (unlike Java).

If it is safe, then would -g always compare true with foo()?

(The above is not true for int in 2's complement).

Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
P45 Imminent
  • 8,319
  • 4
  • 35
  • 78
  • There is an implicit assumption of symmetric range for a floating point type,but I don't think it's formalized anywhere. So, in practice safe, but formally possibly not guaranteed. Note: a floating point type usually/always uses explicit sign bit. – Cheers and hth. - Alf Jun 12 '15 at 10:00
  • Minus one? Can I improve this in any way? – P45 Imminent Jun 12 '15 at 10:04
  • Related: http://stackoverflow.com/q/5777484/1207195 – Adriano Repetti Jun 12 '15 at 10:17
  • 1
    @P45Imminent: Sorry about that, I just felt you're concerned with insignificant details. `int` has problems because of the limited range, with `float`s that surely not a practical concern. Assume it just works and move on... Don't worry though, I'm sure you'll get plenty of upvotes from overly-enthusiastic language lawyers ;) – Karoly Horvath Jun 12 '15 at 10:22
  • @KarolyHorvath: the *standard* doesn't have a problem with the limited ranges – the minimum for char, short, int and so on are the same as the maximum, but with the opposite sign. It's "[t]heir implementation-defined values" that causes P45's concern (so it may need clarification on what implementation is referred to). – Jongware Jun 12 '15 at 10:56
  • 1
    @KarolyHorvath: Huh? Nonsense! Working with floating-point is _precisely_ when you want to start spending a little time being diligent and thinking these things through. – Lightness Races in Orbit Jun 12 '15 at 11:06
  • @LightnessRacesinOrbit: Know about imprecision (==) and NaN. That's it. Of course, if you work on the implementation of floating-point stuff on a compiler or writing the standard, that's a totally differernt issue. But I often see people suggesting reading some 100 page documents about floating-point arithmetic that *every* programmer should know about. I find that (with the stress on every) ludicrous. Am I too pragmatic? I don't think so. – Karoly Horvath Jun 12 '15 at 11:30
  • @KarolyHorvath: Did I link you to that document? I don't think so. You're still wrong. :) – Lightness Races in Orbit Jun 12 '15 at 11:31
  • @LightnessRacesinOrbit: https://www.youtube.com/watch?v=pWdd6_ZxX8c :D – Karoly Horvath Jun 12 '15 at 11:34
  • @P45Imminent: be careful to not mix up *specifation* and *implementation*. "The above is not true for `int` in 2's complement" - it **is** true for the Specification, but it shows that if you only rely on a certain Implementation you can run into problems. As long as you don't use signed values outside what the Specification guarantees, you should be safe. The same could be true for your `double` trouble. – Jongware Jun 12 '15 at 12:56
  • .. to clarify (after some further thinking): "The above is not true for `int` in 2's complement" presupposes that calculations on `int` are implemented with 2's complement math. Now *that* is not in the Specification, and an implementation is free to use other methods. – Jongware Jun 12 '15 at 13:01
  • "`-g` always compare true with `foo()`" fails when `g` is a "not-a-number". – chux - Reinstate Monica Jun 12 '15 at 13:08

1 Answers1

5

Floating types are defined by §5.2.4.2.2 of the C standard (draft N1570 at least):

The characteristics of floating types are defined in terms of a model that describes a representation of floating-point numbers and values that provide information about an implementation’s floating-point arithmetic.21) The following parameters are used to define the model for each floating-point type:

  • s sign (±1)
  • b base or radix of exponent representation (an integer > 1)
  • e exponent (an integer between a minimum emin and a maximum emax)
  • p precision (the number of base-b digits in the significand)
  • fk nonnegative integers less than b (the significand digits)

A floating-point number (x) is defined by the following model:

So yes, that expression is somewhat safe, except in the case where foo returned one of the "other kinds of floating point numbers" not specified by the standard:

In addition to normalized floating-point numbers ( f1 > 0 if x ≠ 0), floating types may be able to contain other kinds of floating-point numbers, such as subnormal floating-point numbers (x ≠ 0, e = emin, f1 = 0) and unnormalized floating-point numbers (x ≠ 0, e > emin, f1 = 0), and values that are not floating-point numbers, such as infinities and NaNs.

and:

An implementation may give zero and values that are not floating-point numbers (such as infinities and NaNs) a sign or may leave them unsigned.

There are probably other caveats to this, but the standard goes in a fair bit of details about the characteristics of these types. You can read all about them in this publicly available draft.

Shoe
  • 74,840
  • 36
  • 166
  • 272
  • 1
    Why "somewhat"? Based on the draft definition, I would think that it's *always* safe. "Sign" is a singular value - it is `1` for positive and `-1` for negative numbers. Flipping this bit does not influence any of the other bits, so according to the description, all that changes is that `+x` becomes `-x`. (Sorry for the edit) – Jongware Jun 12 '15 at 10:36
  • 2
    It weirds out for `NaN`s. They seem to negate at least in IEEE754, but of course they don't compare equal with themselves so that requirement breaks. – unwind Jun 12 '15 at 12:22
  • @unwind I don't think IEEE assigns a meaning to the sign bit of a NaN, but for sure some formatting routines which can display NaN will show "-NaN" if it's set. Probably just because "inf" needs that. It's possible, and common, to implement 'negate' as 'change the sign bit' without regard to the rest of the number (but maybe in some cases, depending on FP settings, it should raise an exception if it's a nan?). – greggo Jul 30 '15 at 17:06