0

In java, is there a difference between negating a variable vs multiplying a variable by a float minus one, if the variable is also a float?

Marek Krzeminski
  • 1,308
  • 3
  • 15
  • 40
  • 3
    The latter should result in a floating point negative number. As for the first, it depends on the type of `x`. – npinti Apr 25 '16 at 12:46
  • Yes, as @npinti pointed out, -x will be integer or double or whatever type x was and multiplying it with -1.0f will implicitly convert it to float. – Vucko Apr 25 '16 at 12:48
  • @Vucko: Yes, but he writes that the variable is also float. – Frank Puffer Apr 25 '16 at 12:49

4 Answers4

2

Java uses binary floating point representation of IEEE, with the sign represented by a separate bit. Both multiplying by -1 and inverting the sign with -x are done by flipping this sign bit, while keeping the rest of the representation unchanged. That is why there is no difference in the result, because -1.0f has an exact representation, and there is no chance of changing the precision of representation of x.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
2

In JLS §15.15.4 "Unary Minus Operator -", we find that

For floating-point values, negation is not the same as subtraction from zero, because if x is +0.0, then 0.0-x is +0.0, but -x is -0.0. Unary minus merely inverts the sign of a floating-point number. Special cases of interest:

If the operand is NaN, the result is NaN. (Recall that NaN has no sign (§4.2.3).)

If the operand is an infinity, the result is the infinity of opposite sign.

If the operand is a zero, the result is the zero of opposite sign.

(Highlight mine)

The difference can be seen in the emitted bytecode. Unary minus is a simple fneg, while (-1f * x) results in an fload and fmul, which is likely slightly slower.

I have no idea if the JIT compiler will optimize it.

For readability, using -x is usually better.

Polygnome
  • 7,639
  • 2
  • 37
  • 57
  • Does Java follow IEEE 754-2008? It specifies negation as a bit-level operation affecting NaN : "5.5.1 Sign bit operations. Implementations shall provide the following homogeneous quiet-computational sign bit operations for all supported arithmetic formats; they only affect the sign bit. The operations treat floating-point numbers and NaNs alike, and signal no exception. These operations may propagate non-canonical encodings. [...] negate(x) copies a floating-point operand x to a destination in the same format, reversing the sign bit. negate(x) is not the same as subtraction(0, x) (see 6.3). – njuffa Apr 25 '16 at 16:02
  • IEEE 754-2008 states further with regard to the sign bit of NaNs:: "6.3 The sign bit. When either an input or result is NaN, this standard does not interpret the sign of a NaN. Note, however, that operations on bit strings — copy, negate, abs, copySign — specify the sign bit of a NaN result, sometimes based upon the sign bit of a NaN operand. The logical predicate totalOrder is also affected by the sign bit of a NaN operand." – njuffa Apr 25 '16 at 16:04
  • By default, Java takes some liberties and allows higher-precision intermediate results. Using the `strictfp` keyword, Java obeys IEEE 754 - but according to http://stackoverflow.com/questions/11474424/any-ieee754r-compliant-implementations-for-java Java did not adopt the new 754-2008 variant. – Polygnome Apr 25 '16 at 16:17
1

If x was already a float then there is no difference. However the -x is more readable.

joe pelletier
  • 390
  • 2
  • 12
1

There is a slight difference in the bytecode produced:

float one(float x) {
  return -x;
}

float two(float x) {
  return x * -1.f;
}

float three(float x) {
  return -1.f * x;
}

Decompile to:

  float one(float);
    Code:
       0: fload_1
       1: fneg
       2: freturn

  float two(float);
    Code:
       0: fload_1
       1: ldc           #2                  // float -1.0f
       3: fmul
       4: freturn

  float three(float);
    Code:
       0: ldc           #2                  // float -1.0f
       2: fload_1
       3: fmul
       4: freturn

I would imagine that the fneg instruction is slightly faster than the fload_1/fmul; but the difference is likely to be negligible (and very possibly optimized out by the JIT).

Andy Turner
  • 137,514
  • 11
  • 162
  • 243