2

What is faster from a code execution perspective:

double a = 1.234;
double minus_a = -a;

or:

double a = 1.234;
double minus_a = a * -1;

Does the second case actually perform floating point multiplication? Or is the compiler smart enough to optimize the second case to be the same as the first?

Arvind
  • 93
  • 8
  • There is no reason to suppose that the first would ever be slower than the second, and it is both shorter and more conventional. Why would you even consider the second? – John Bollinger May 30 '17 at 18:01
  • Are you aware that you can [view the compiled IL](https://msdn.microsoft.com/en-us/library/f7dy01k1(v=vs.110).aspx) and find out for yourself? – BJ Myers May 30 '17 at 18:01
  • Negating a value is much simpler and readable than multiplication! – Salah Akbari May 30 '17 at 18:02
  • The difference if any is so small that should not be noticeable at all, so write the way you prefer. – Gusman May 30 '17 at 18:06
  • Decompiled code from case 2 above looks just like the original code: it invokes multiplication with -1 instead of using the unary negation operator. I much prefer case 1 but am looking for data to prove that case 1 is faster -- short of writing my own benchmark test. – Arvind May 30 '17 at 18:07

1 Answers1

6

Tested with the 64bit JIT of .NET 4, other JITs such as the old 32bit JIT or the newer RyuJIT can be different (actually the 32bit old JIT must do something else since it does not use SSE), though 64bit Core CLR 5.0 still does the same thing.

-x translates into

vmovsd      xmm1,qword ptr [00000050h] ; the constant is -0.0, so only the sign bit is set
vxorpd      xmm0,xmm0,xmm1 ; literally flip the sign

x * -1 into

vmulsd      xmm0,xmm0,mmword ptr [00000048h] ; -1.0

Yes, very literal.

As for speed, you can pick your model from here and compare, but vxorpd will always be faster than vmulsd.

Could it have optimized x * -1 to a XOR? Maybe. There are some quirky cases in which that does not do the same thing, eg when DAZ or FTZ are set (they affect the operation of vmulsd in the case of denormal values, but vxorps ignores those flags, it's always a pure xor). But there is no official way to use those features in .NET.

harold
  • 61,398
  • 6
  • 86
  • 164
  • Awesome. Just what I was looking for: "* -1" invokes floating point multiplication! No optimization here. – Arvind May 30 '17 at 18:22
  • I did write a simple benchmark. Results: Negation elapsed time 00:00:02.6422642--- *-1 elapsed time 00:00:03.4353435-------- So float multiplication is slower by about 30%. – Arvind May 30 '17 at 18:41