<< Back to previous view

[PCC-413] complex divide wrong Created: 25/Dec/12  Updated: 02/Jul/14

Status: Resolved
Project: pcc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major
Reporter: Fred J. Tydeman Assignee: Anders Magnusson
Resolution: Fixed Votes: 0
Environment: Intel x86/x87, Fedora Core 16, pcc 2011/12/16


 Description   
Complex divide gets wrong answer. Either divide is bad or alignment is wrong. The imaginary part of the result
has the exponent in the wrong place. So, instead of a NaN, it gets a denormal number. Complex numbers are
supposed to be treated as an array of two floating-point numbers.

static _Complex double res, left, right;
  res = left / right; /* both left and right are 0.0+0.0*I */

Produces:
res .im=00000000fff80000=+2.12173675827594550e-314
want .im=fff8000000000000=-nan
left .re=0000000000000000=+0.00000000000000000e+00
left .im=0000000000000000=+0.00000000000000000e+00
right.re=0000000000000000=+0.00000000000000000e+00
right.im=0000000000000000=+0.00000000000000000e+00


 Comments   
Comment by Fred J. Tydeman [ 28/Dec/12 06:10 PM ]
Another failure:
#include <float.h>
 float _Complex res, left, right;
  left = 0.f + FLT_EPSILON * I;
  right = left;
  res = left / right;

 res should be 1.f + 0.f*I
Instead my test program gets garbage for the imaginary part of res:
res .im=4e706848=+1.00834150400000000e+09
want .im=00000000=+0.00000000000000000e+00
left .re=00000000=+0.00000000000000000e+00
left .im=34000000=+1.19209289550781250e-07
right.re=00000000=+0.00000000000000000e+00
right.im=34000000=+1.19209289550781250e-07

Letting
 left = right = 0.f + 1.f/3.f * I;
gets the same wrong imaginary part for res:
res .im=4e706848=+1.00834150400000000e+09
want .im=00000000=+0.00000000000000000e+00
left .re=00000000=+0.00000000000000000e+00
left .im=3eaaaaaa=+3.33333313465118408e-01
right.re=00000000=+0.00000000000000000e+00
right.im=3eaaaaaa=+3.33333313465118408e-01


The same kind of issue happens with
 double _Complex res, left, right;
 left = right = 0.0 + DBL_EPSILON * I;
 res = left / right;
gets:
res .im=08048a2ebfdf204c=+4.85992534235132247e-270
want .im=0000000000000000=+0.00000000000000000e+00
left .re=0000000000000000=+0.00000000000000000e+00
left .im=3cb0000000000000=+2.22044604925031308e-16
right.re=0000000000000000=+0.00000000000000000e+00
right.im=3cb0000000000000=+2.22044604925031308e-16


Comment by Anders Magnusson [ 30/Apr/14 05:57 PM ]
Complex div fixed now.
Comment by Fred J. Tydeman [ 02/Jun/14 03:37 PM ]
This still has problems in 2014/04/20 version of pcc.
I am now testing the 64-bit version on an Intel Core 2 Duo.
The OS is Linux Fedora Core 20.
Comment by Fred J. Tydeman [ 02/Jun/14 08:03 PM ]
Here is a test that fails 2012/04/20 version

#include <complex.h>
#include <stdio.h>
static float complex fc1; /* 0.f + 0.f*I */
static float f; /* 0.f */
int main(void){
  fc1 = fc1 / f;
  (void)printf("%g, %g\n", creal(fc1), cimag(fc1)); /* should be nan, nan */
  return 0;
}
Comment by Fred J. Tydeman [ 04/Jun/14 08:25 PM ]
Here is another failure:

#include <float.h>
#include <complex.h>
#include <stdio.h>

int main(void){
  float complex fc1, fc2, fc3;
  fc1 = 0.f + I*0.f;
  fc2 = 0.f + I*FLT_MIN;
  fc3 = fc1 / fc2; /* zero / non-zero should be zero */
  (void)printf("fc1=(%g,%g)\n", creal(fc1), cimag(fc1));
  (void)printf("fc2=(%g,%g)\n", creal(fc2), cimag(fc2));
  (void)printf("fc3=(%g,%g)\n", creal(fc3), cimag(fc3));
  if( (0.f != creal(fc3)) || (0.f != cimag(fc3)) ){
    (void)printf("Bad\n");
  }
  return 0;
}
Comment by Anders Magnusson [ 06/Jun/14 01:25 PM ]
The syntax for div seems a little more complicated than was initially thought, have to rewrite div handling.
Comment by Fred J. Tydeman [ 06/Jun/14 05:00 PM ]
Look at C99 or C11 G.5.1 on some of the special cases. Also,
http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1399.txt
Comment by Anders Magnusson [ 06/Jun/14 05:31 PM ]
Thanks for the pointers.
I need to find a way to deal with this compiler-wise without needing to add -lm for complex numbers.
Comment by Anders Magnusson [ 23/Jun/14 06:09 PM ]
Interesting, the last of your examples failed with clang (but worked with gcc 4.8).

minint-rmn60om:/Users/ragge/tmp >clang -O cmplxdiv.c
minint-rmn60om:/Users/ragge/tmp >./a.out
fc1=(0,0)
fc2=(0,1.17549e-38)
fc3=(nan,nan)
Bad
minint-rmn60om:/Users/ragge/tmp >clang --version
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.1.0
Thread model: posix
Comment by Fred J. Tydeman [ 23/Jun/14 07:44 PM ]
A related problem in pcc and clang, is real / complex.

http://llvm.org/bugs/show_bug.cgi?id=20083
Comment by Anders Magnusson [ 02/Jul/14 02:15 PM ]
Now these tests at least works. I rewrote the complex div logic, following the C99 guidelines.
Generated at Mon Sep 22 18:17:04 CEST 2014 using JIRA Enterprise Edition, Version: 3.13.1-#333.