NO

Author Topic: Complex Float gives surprising result  (Read 15975 times)

ofniw

  • Guest
Complex Float gives surprising result
« on: August 10, 2008, 02:17:51 PM »
Hi all,

I am very delighted by the addition of the complex data type with the latest version 5 of the compiler. Pelles thank you very much.

I´m using C-language to translate mathematical algorithms which I use from Visual Basic 6. ( VB6 for easy GUI programming )

In order to test the new complex types I have coded two simple routines, each adding two complex numbers :

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <oleauto.h>
#include <tgmath.h>
/*
 * Include our "interface" file and define a symbol
 * to indicate that we are *building* the DLL.
 */
#define _SIMPDLL_
#include "simpdll.h"
.
.
.
.

SIMPDLLAPI _Complex float  WINAPI c_add(float complex * a1, float complex * a2 ){
float complex c;
c=*a1+ *a2;
return c;

}

SIMPDLLAPI double complex  WINAPI dc_add(double complex* a1,  double complex* a2) {
double complex c;
c=*a1+*a2;
return c;
}

I translate these routine ( with the normal Windows overhead ) to a dll which I call from VB6.
I´m using the latest version of the 32bit version 5 compiler.


In VB 6 I declare the following complex types
Type Complex
    r As Single                 'Real
    i As Single                 'Imaginary
End Type
Type Complex_16
    r As Double                 'Real
    i As Double                 'Imaginy
End Type

With type Complex the data is stored in two consecutive single precision ( 4 bytes ) floating points.
With type Complex_16 the data is stored in two consecutive double precision ( 8 bytes ) floating points.

VB declares the two external routines as:

Declare Function c_add_c Lib ".\simpdll\SimpDLL.DLL" Alias "c_add" (a As Complex, c As Complex) As Complex
Declare Function dc_add_c Lib ".\simpdll\SimpDLL.DLL" Alias "dc_add" (a As Complex_16, b As Complex_16) As Complex_16

I call the routines from vb6 with
.
.
.
Dim c2 As Complex_16, c3 As Complex_16, c4 As Complex_16
Dim c5 As Complex, c6 As Complex, c7 As Complex
.
.
.
    Case Is = 8 ' Complex double precision Addition
        c4.r = 7
        c4.i = 30
        c2.r = 8
        c2.i = 31
        c3 = dc_add_c(c4, c2)
.
.
.

    Case Is = 9 ' Complex single precision, Addition
        c7.r = 7
        c7.i = 30
        c5.r = 8
        c5.i = 31
        c6 = c_add_c(c7, c5)
.
.
.
The surprising thing now is, the double precision routine gives the correct result ( via c3 ), the single precision routine delivers some nonsense in c6.

Using the debugger I get the following display after entering c_add
Name   Wert                                  Typ                             Adresse
a1        8+31i                                 float_Complex *8         0012F574
a2     1.74135e-39+5.89257e-39i       float_Complex *8         0012F61C
c       1.7413e-39+5.89477e-39i        float_Complex *8         0012F318

I searched the memory and found a1 at 0012F520 and a2 at 0012F574, not a1.

So, now I'm not sure,if I´m supposed to use the compiler the way I use it. However the double precision function works. So, may be I'm doing something wrong in calling the single precision routine, or the way the arguments are transfered is different for the single precision case, or there is a bug in the compiler.

Any idea ?

Regards

JohnF

  • Guest
Re: Complex Float gives surprising result
« Reply #1 on: August 10, 2008, 04:09:15 PM »
I don't know much about VB but shouldn't you be declaring the vars as ByRef

Declare Function c_add_c Lib ".\simpdll\SimpDLL.DLL" Alias "c_add" (ByRef a As Complex, ByRef c As Complex) As Complex
Declare Function dc_add_c Lib ".\simpdll\SimpDLL.DLL" Alias "dc_add" (ByRef a As Complex_16, ByRef b As Complex_16) As Complex_16

Here is a sample listing that shows your functions work the same as an ordinary complex add, so the problem I think must be in you VB code or VB calls.

Code: [Select]
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <complex.h>


float complex WINAPI fc_add(float complex * a1, float complex * a2)
{
float complex fc;
fc = *a1 + *a2;
return fc;
}

double complex WINAPI dc_add(double complex * a1, double complex * a2)
{
double complex dc;
dc = *a1 + *a2;
return dc;
}

int main(void)
{
double complex dc2, dc3, dc4;
float complex fc5, fc6, fc7;

dc4 = 7+I*30;
dc2 = 8+I*31;
dc3 = dc_add(&dc4, &dc2);

// printf the result of dc_add()
printf("dc3 = %f, %f\n", creal(dc3), cimag(dc3));

// check dc_add
dc3 = dc4 + dc2;
printf("dc3 = %f, %f\n", creal(dc3), cimag(dc3));

fc7 = 7+I*30;
fc5 = 8+I*31;
fc6 = fc_add(&fc7, &fc5);

// printf the result of fc_add()
  printf("fc6 = %f, %f\n", crealf(fc6), cimagf(fc6));

// check fc_add
fc6 = fc7 + fc5;
  printf("fc6 = %f, %f\n", crealf(fc6), cimagf(fc6));

return 0;
}

John
« Last Edit: August 10, 2008, 04:50:02 PM by JohnF »

ofniw

  • Guest
Re: Complex Float gives surprising result
« Reply #2 on: August 11, 2008, 09:56:17 PM »
JohnF, thank you very much for your immediate reply. It is correct, that the call from VB6 has to use the byref convention. However, this is the default. In order not to miss any chance, I added the byref keyword and nothing changed, the single precision add didn't work, the double precision worked.

In the meantime, I also believe, that there is something wrong in passing the addresses of the variables to the subroutine. The question is on which side, VB6 or PellesC.

So I did another test. I defined an own complex type called COMPLEX1:

typedef struct complex1 {
   float r;      // Real
   float i;      // Imag
}COMPLEX1;

Then I replaced the c_add function by:

SIMPDLLAPI COMPLEX1  WINAPI c_add(COMPLEX1 * a1,COMPLEX1 * a2 ){
COMPLEX1 c;
c.r=a1->r+ a2->r;
c.i=a1->i+ a2->i;
return c;

}

And this worked. So I believe, the problem is not with VB6, also because the double precision version works correctly.

Regards

JohnF

  • Guest
Re: Complex Float gives surprising result
« Reply #3 on: August 11, 2008, 11:11:11 PM »
Well, I did another test with a DLL, all ok. So I still reckon the problem is not clear. If it works with a PellesC DLL it should work from VB provided VB is doing the same thing.

Try observing the addresses of the variables from both your VB app and the DLL and see if there is a problem there. An easy way is to use a MessageBox.

Is it possible that the VB float struct has padding and the double struct does not have padding?

If you did your COMPLEX1 test in C that is not much of a test as my code had already done that.

Try to get the size of the VB complex float struct.

John
 

« Last Edit: August 11, 2008, 11:23:23 PM by JohnF »

ofniw

  • Guest
Re: Complex Float gives surprising result
« Reply #4 on: August 12, 2008, 09:30:32 PM »
Thank you for your response.

I followed your advice and did the following:
1. Got the location of the vb6 structures
2. Using the debugger and my "own complex type" examined the pointers in the c function
3. Using the built in complex type examined the pointers in the c function

These are the results:
1.
Thats the code snippet from VB6

        c7.r = 7
        c7.i = 30
        c5.r = 8
        c5.i = 31
        c6 = c_add_c(c7, c5)

I have placed a breakpoint before the function call. At that breakpoint I get for the addresses of the complex structures:

?hex(varptr(c7))
13F520
?hex(varptr(c7.r))
13F520
?hex(varptr(c7.i))
13F524
?hex(varptr(c5))
13F574
?hex(varptr(c5.r))
13F574
?hex(varptr(c5.i))
13F578
This is what I had already written, that the values are stored in consecutive locations.
#######################
Now to the c-side
2.
With the construct

SIMPDLLAPI COMPLEX1  WINAPI c_add(COMPLEX1 * a1,COMPLEX1 * a2 ){
COMPLEX1 c;
c.r=a1->r+ a2->r;
c.i=a1->i+ a2->i;
return c;

In the debugger I get the information

Name                     Value                                      Type                                  Address 
a1                           {...}                                     struct*                               0013F520
       r                      7                                          struct*                               0013F520
       i                       30                                        struct*                               0013F524
a2                           {...}                                     struct*                               0013F574
       r                      8                                          struct*                               0013F574
       i                       31                                        struct*                               0013F578

which is exactly the same location that I got in VB6.
3.
Now, without changing anything in VB6 but using the construct

SIMPDLLAPI float complex  WINAPI c_add(float complex * a1, float complex * a2 ){
float complex c;
c=*a1+ *a2;
return c;

}
From the debugger I get

Name   Value                                 Type                           Address
a1        8+31i                                 float_Complex *8         0012F574
a2     1.74135e-39+5.89257e-39i       float_Complex *8         0012F61C
c       1.7413e-39+5.89477e-39i        float_Complex *8         0012F318

So obviously, *a1 and *a2 point to the wrong location. They should point at

*a1    0012F520
*a2    0012F574


I hope this examination helps.

Regards


JohnF

  • Guest
Re: Complex Float gives surprising result
« Reply #5 on: August 12, 2008, 10:40:13 PM »
Using a DLL I get the correct addresses so I'm stumped.

Why would VB cause a difference between your COMPLEX1 struct and a Complex type? I can't guess at that.

Of course you are suggesting that the two different functions in PellesC are causing the problem.

Code: [Select]
SIMPDLLAPI float complex  WINAPI c_add(float complex * a1, float complex * a2)

SIMPDLLAPI COMPLEX1  WINAPI c_add(COMPLEX1 * a1,COMPLEX1 * a2 )

The fact that it works with my DLL suggests that there is no problem.

Have you tried making a test using a C listing and your DLL and see what happens then ?

Here is my listing again. Put the lib of your dll and the dll in the same folder as the C app and run the code below. Change the function calls to suit the names you have used in your dll and of course the name of your dll.

Code: [Select]
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <complex.h>

#pragma lib "yourdll.lib" // your name here


float complex WINAPI fc_add(float complex * a1, float complex * a2);
double complex WINAPI dc_add(double complex * a1, double complex * a2);

int main(void)
{
double complex dc2, dc3, dc4;
float complex fc5, fc6, fc7;

dc4 = 7+I*30;
dc2 = 8+I*31;
dc3 = dc_add(&dc4, &dc2);

// printf the result of dc_add()
printf("dc3 = %f+%fi\n", creal(dc3), cimag(dc3));

// check dc_add
dc3 = dc4 + dc2;
printf("dc3 = %f+%fi\n", creal(dc3), cimag(dc3));

fc7 = 7+I*30;
fc5 = 8+I*31;
fc6 = fc_add(&fc7, &fc5);

// printf the result of fc_add()
  printf("fc6 = %f+%fi\n", crealf(fc6), cimagf(fc6));

// check fc_add
fc6 = fc7 + fc5;
  printf("fc6 = %f+%fi\n", crealf(fc6), cimagf(fc6));

return 0;
}

John

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2091
Re: Complex Float gives surprising result
« Reply #6 on: August 13, 2008, 10:21:49 AM »
Test this:
Code: [Select]
Attribute VB_Name = "Module1"
Type Complex
    r As Single                 'Real
    i As Single                 'Imaginary
End Type
Type Complex_16
    r As Double                 'Real
    i As Double                 'Imaginy
End Type
Type ComplexX
    r As Single                 'Real
    i As Single                 'Imaginary
    filler As Double
End Type


'Declare Function fc_add Lib "Complex_DLL.DLL" (ByRef a As Complex, ByRef c As Complex) As Complex
Declare Function fc_add Lib "Complex_DLL.DLL" (ByRef a As Complex, ByRef c As Complex) As ComplexX
Declare Function dc_add Lib "Complex_DLL.DLL" (ByRef a As Complex_16, ByRef b As Complex_16) As Complex_16

Sub Main()

Dim c2 As Complex_16, c3 As Complex_16, c4 As Complex_16
Dim c5 As Complex, c6 As Complex, c7 As Complex
Dim cx As ComplexX

       ' Complex double precision Addition
        c4.r = 7
        c4.i = 30
        c2.r = 8
        c2.i = 31
        c3 = dc_add(c4, c2)
       
        ' Complex single precision, Addition
        c7.r = 7
        c7.i = 30
        c5.r = 8
        c5.i = 31
        'c6 = fc_add(c7, c5)
        cx = fc_add(c7, c5)
       
End Sub
May the source be with you

JohnF

  • Guest
Re: Complex Float gives surprising result
« Reply #7 on: August 13, 2008, 10:56:50 AM »
Timovjl, what have you found? I can't run VB stuff.

John

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2091
Re: Complex Float gives surprising result
« Reply #8 on: August 13, 2008, 01:59:17 PM »
Some kind of stack problem.
With filler it can be avoided.

Code: [Select]
CPU Disasm
Address   Hex dump          Command                                  Comments
10001000    55              PUSH EBP
10001001    89E5            MOV EBP,ESP
10001003    83EC 08         SUB ESP,8
10001006    8B45 0C         MOV EAX,DWORD PTR SS:[EBP+0C]
10001009    D940 04         FLD DWORD PTR DS:[EAX+4]
1000100C    D900            FLD DWORD PTR DS:[EAX]
1000100E    8B45 10         MOV EAX,DWORD PTR SS:[EBP+10]
10001011    D800            FADD DWORD PTR DS:[EAX]                  ; FLOAT 8.000000000000000
10001013    D9C9            FXCH ST(1)
10001015    D840 04         FADD DWORD PTR DS:[EAX+4]
10001018    D9C9            FXCH ST(1)
1000101A    D95D F8         FSTP DWORD PTR SS:[EBP-8]
1000101D    D95D FC         FSTP DWORD PTR SS:[EBP-4]
10001020    8B45 08         MOV EAX,DWORD PTR SS:[EBP+8]
10001023    D945 FC         FLD DWORD PTR SS:[EBP-4]
10001026    D945 F8         FLD DWORD PTR SS:[EBP-8]
10001029    D918            FSTP DWORD PTR DS:[EAX]
1000102B    D958 04         FSTP DWORD PTR DS:[EAX+4]
1000102E    89EC            MOV ESP,EBP
10001030    5D              POP EBP
10001031    C2 0C00         RETN 0C

10001034    55              PUSH EBP
10001035    89E5            MOV EBP,ESP
10001037    83EC 10         SUB ESP,10
1000103A    8B45 0C         MOV EAX,DWORD PTR SS:[EBP+0C]
1000103D    DD40 08         FLD QWORD PTR DS:[EAX+8]
10001040    DD00            FLD QWORD PTR DS:[EAX]
10001042    8B45 10         MOV EAX,DWORD PTR SS:[EBP+10]
10001045    DC00            FADD QWORD PTR DS:[EAX]
10001047    D9C9            FXCH ST(1)
10001049    DC40 08         FADD QWORD PTR DS:[EAX+8]
1000104C    D9C9            FXCH ST(1)
1000104E    DD5D F0         FSTP QWORD PTR SS:[EBP-10]
10001051    DD5D F8         FSTP QWORD PTR SS:[EBP-8]
10001054    8B45 08         MOV EAX,DWORD PTR SS:[EBP+8]
10001057    DD45 F8         FLD QWORD PTR SS:[EBP-8]
1000105A    DD45 F0         FLD QWORD PTR SS:[EBP-10]
1000105D    DD18            FSTP QWORD PTR DS:[EAX]
1000105F    DD58 08         FSTP QWORD PTR DS:[EAX+8]
10001062    89EC            MOV ESP,EBP
10001064    5D              POP EBP
10001065    C2 0C00         RETN 0C
May the source be with you

JohnF

  • Guest
Re: Complex Float gives surprising result
« Reply #9 on: August 13, 2008, 04:52:48 PM »
Ok, thanks.

John

ofniw

  • Guest
Re: Complex Float gives surprising result
« Reply #10 on: August 13, 2008, 08:15:47 PM »
Good evening JohnF and timovjl

Hello JohnF,
I first tried your proposed small C program and it gave the correct result with the same dll I used with the VB6 program.

Hello timovjl,
then I tried your redefinition complexX of the type complex ( adding filler ). Then I got the correct result with VB6.

Thanks, however, I do not understand what`s going on.

Regards

JohnF

  • Guest
Re: Complex Float gives surprising result
« Reply #11 on: August 14, 2008, 09:29:48 AM »
Yes it's strange. I did a test with VC6 and the Complex struct with two floats crashes whereas the ComplexX struct with an extra double does not.

Haven't seen Pelle for a while, hope he sees this thread.

EDIT: The above also crashes in a PellesC listing.

John
« Last Edit: August 14, 2008, 10:47:10 AM by JohnF »

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2096
Re: Complex Float gives surprising result
« Reply #12 on: August 14, 2008, 05:05:08 PM »
Dear all,
I had not enaugh time to check everything, and I, as John, don't have VB available. But as far as I can see you are returning automatic variables pinters from your programs  ::), this kind of variables as you well know are destroyed when the subroutine exits. This explains the crash, and maybe the wrong addressing (due to processo memory mappings).
I'm not sure this will solve, but I suggest to change the dll code to:
Code: [Select]
complex float   __c_float;
SIMPDLLAPI _Complex float  WINAPI *c_add(float complex * a1, float complex * a2 ){
__c_float=*a1+ *a2;
return &__c_float;
}

complex double   __c_double;
SIMPDLLAPI double complex  WINAPI *dc_add(double complex* a1,  double complex* a2) {
__c_double=*a1+*a2;
return &__c_double;
}
Please test, I'm curious....
It is better to be hated for what you are than to be loved for what you are not. - Andre Gide

ofniw

  • Guest
Re: Complex Float gives surprising result
« Reply #13 on: August 14, 2008, 07:12:02 PM »
Hello Frankie,
I have tested.

I have used 4 setups

Setup 1 and Setup 2 use the program as you suggested

Setup 1:
--------
Type Complex
    r As Single                 'Real
    i As Single                 'Imaginary
End Type
Type Complex_16
    r As Double                 'Real
    i As Double                 'Imaginary
End Type

Result:
Simple precision: Wrong result
Double precision: Crash

Setup 2:
--------
Type ComplexX
    r As Single                 'Real
    i As Single                 'Imaginary
    filler As Double
End Type
Type Complex_16
    r As Double                 'Real
    i As Double                 'Imaginary
End Type

Result:
Simple precision: Crash
Double precision: Crash

Setup 3 and Setup 4 use the following program

complex float   __c_float;
SIMPDLLAPI _Complex float  WINAPI c_add(float complex * a1, float complex * a2 ){
__c_float=*a1+ *a2;
return __c_float;
}

complex double   __c_double;
SIMPDLLAPI double complex  WINAPI dc_add(double complex* a1,  double complex* a2) {
__c_double=*a1+*a2;
return __c_double;
}

Setup 3:
--------
Type Complex
    r As Single                 'Real
    i As Single                 'Imaginary
End Type
Type Complex_16
    r As Double                 'Real
    i As Double                 'Imaginary
End Type

Result:
Double precision: Correct result.
Single precision: Wrong result


Setup 4
--------
With the definition
'    filler As Double
Type ComplexX
    r As Single                 'Real
    i As Single                 'Imaginary
    filler As Double
End Type
Type Complex_16
    r As Double                 'Real
    i As Double                 'Imaginary
End Type

Result:
Double precision: Correct result.
Single precision: Correct result


So sorry, your suggestion did not work.

Regards

JohnF

  • Guest
Re: Complex Float gives surprising result
« Reply #14 on: August 14, 2008, 08:08:07 PM »
Dear all,
I had not enaugh time to check everything, and I, as John, don't have VB available. But as far as I can see you are returning automatic variables pinters from your programs  ::), this kind of variables as you well know are destroyed when the subroutine exits. This explains the crash, and maybe the wrong addressing (due to processo memory mappings).

All the functions in the DLL were returning structs not pointers. So in this case the value/s in the struct is/are copied to the receiving var.

Example
Code: [Select]
SIMPDLLAPI float complex WINAPI c_add(float complex * a1, float complex * a2 )
{
float complex c;
c=*a1+ *a2;
return c;
}

There _is_ something wrong here.

John
« Last Edit: August 14, 2008, 09:04:49 PM by JohnF »