Page 1 of 1

XC and long long, float, double and long double

Posted: Wed Mar 21, 2018 11:26 am
by aclassifier
Does XC support long long, float, double and long double?

In xTIMEcomposer User Guide chapter XS1 Data Types it doesn't. I have searched through some of the release notes, like this but failed to find anything about "64" or the like.

This compiles with xTIMEcomposer 14.3.2:

Code: Select all

vvoid test (void) {

    long        mylong       = 0xfffffffe; // -2
    long long   mylonglong   = 0xfffffffe; // Should have been 4294967294 if 64 bits wide. But is -2

    for (unsigned i=0; i<5; i++) {
        printf ("LL(%u): mylong:%d - mylonglong:%d\n",
                i, mylong, mylonglong);

        mylong++;
        mylonglong++;
    }

    float       myfloat      = -2.1;
    int         myfloatint   = (int) myfloat;
    double      mydouble     = -2.1;
    long double mylongdouble = -2.1;

    for (unsigned i=0; i<5; i++) {
        printf ("F(%u) myfloat:%f - myfloatint:%d - mydouble:%f mylongdouble:%f\n",
                i, myfloat, myfloatint, mydouble,  mylongdouble);

        myfloat      = myfloat + 1.0;
        myfloatint   = (int) myfloat;
        mydouble     = mydouble + 1.0;
        mylongdouble = mylongdouble +1.0;
    }

}

int main() {
    par {
        test();
    }
 return 0;
}
And here's my log:

Code: Select all

LL(0): mylong:-2 - mylonglong:-2
LL(1): mylong:-1 - mylonglong:-1
LL(2): mylong:0 - mylonglong:0
LL(3): mylong:1 - mylonglong:1
LL(4): mylong:2 - mylonglong:2
F(0) myfloat:-2.100000 - myfloatint:-2 - mydouble:-2.100000 mylongdouble:-2.100000
F(1) myfloat:-1.100000 - myfloatint:-1 - mydouble:-1.100000 mylongdouble:-1.100000
F(2) myfloat:-0.100000 - myfloatint:0 - mydouble:-0.100000 mylongdouble:-0.100000
F(3) myfloat:0.900000 - myfloatint:0 - mydouble:0.900000 mylongdouble:0.900000
F(4) myfloat:1.900000 - myfloatint:1 - mydouble:1.900000 mylongdouble:1.900000
I think this looks like long long == long and that floating formats are supported!?

However, I cannot from the above conclude that double and long double are supported as (64 bits values) by the tests above (since I really don't know how to make that wrap-around that I did with 32->64 bits integer, for IEEE floats)

Comments?

Re: XC and long long, float, double and long double

Posted: Wed Mar 21, 2018 12:37 pm
by akp
Hi,

Try changing your first printf statement to the following and see what you get.

Code: Select all

printf ("LL(%u): mylong:%ld - mylonglong:%lld\n", i, mylong, mylonglong);

Re: XC and long long, float, double and long double

Posted: Wed Mar 21, 2018 1:26 pm
by akp
Try the following for your floating point test. You should see some interesting results. Analysis left to the reader ;-)

Code: Select all

    float       myfloat      = 16777214.0;
    int         myfloatint   = (int) myfloat;
    double      mydouble     = myfloat;
    long double mylongdouble = myfloat;

    for (unsigned i=0; i<5; i++) {
        printf ("F(%u) myfloat:%f - myfloatint:%d - mydouble:%lf mylongdouble:%llf\n",
                i, myfloat, myfloatint, mydouble,  mylongdouble);

        myfloat      = myfloat + 1.0;
        myfloatint   = (int) myfloat;
        mydouble     = mydouble + 1.0;
        mylongdouble = mylongdouble +1.0;
    }

Re: XC and long long, float, double and long double

Posted: Wed Mar 21, 2018 2:43 pm
by aclassifier
Thanks akp! I tried the single 'l' (which didn't work) but didn't discover the "ld", "lf" and "llf" printf qualifiers! After all I only programmed embedded controllers professionally in C for 15 years! And Wikipedia didn't help that much! I really think that since %d and %u work for 8, 16 and 32 bits, ANSI C should have taken it it all the way up (also for 'f') instead of doing a hidden type cast... But I really suspected this was the problem since long long did work akp's code in Porting the Arduino millis(), possible?

Code: Select all

void test (void) {

    long        mylong       = 0xfffffffe; // -2
    long long   mylonglong   = 0xfffffffe; // is 4294967294 since 64 bits wide

    for (unsigned i=0; i<5; i++) {
        printf ("LL(%u): mylong:%ld - mylonglong:%lld\n", i, mylong, mylonglong);

        mylong++;
        mylonglong++;
    }

    float       myfloat      = 16777214.0; // -2 = 0xfffffe (all 24 fraction bits if EEEE 754 single-precision)
    int         myfloatint   = (int) myfloat;
    double      mydouble     = myfloat;
    long double mylongdouble = myfloat;

    for (unsigned i=0; i<5; i++) {
        printf ("F(%u) myfloat:%f - myfloatint:%d - mydouble:%lf mylongdouble:%llf\n",
                i, myfloat, myfloatint, mydouble,  mylongdouble);

        myfloat      = myfloat + 1.0;
        myfloatint   = (int) myfloat;
        mydouble     = mydouble + 1.0;
        mylongdouble = mylongdouble + 1.0;
    }
}

int main() {
    par {
        test();
    }
 return 0;
}
When the fraction 23-bit field of myfloat overflows it does not wrap around. I just assume that is defined semantics(?): It stops at 16777216.000000:

Code: Select all

LL(0): mylong:-2 - mylonglong:4294967294
LL(1): mylong:-1 - mylonglong:4294967295
LL(2): mylong:0 - mylonglong:4294967296
LL(3): mylong:1 - mylonglong:4294967297
LL(4): mylong:2 - mylonglong:4294967298
F(0) myfloat:16777214.000000 - myfloatint:16777214 - mydouble:16777214.000000 mylongdouble:16777214.000000
F(1) myfloat:16777215.000000 - myfloatint:16777215 - mydouble:16777215.000000 mylongdouble:16777215.000000
F(2) myfloat:16777216.000000 - myfloatint:16777216 - mydouble:16777216.000000 mylongdouble:16777216.000000
F(3) myfloat:16777216.000000 - myfloatint:16777216 - mydouble:16777217.000000 mylongdouble:16777217.000000
F(4) myfloat:16777216.000000 - myfloatint:16777216 - mydouble:16777218.000000 mylongdouble:16777218.000000
Also, the mydouble has 52 bits in the fraction field, so it increments nicely.

Thanks! Yes, all of long long, float, double and long double are supported in XC. Again, some documentation work for XMOS, to update some documents!

[1] IEEE 754 single-precision binary floating-point format: binary32
[2] Double-precision floating-point format

Re: XC and long long, float, double and long double

Posted: Wed Mar 21, 2018 3:44 pm
by akp
No problem. The way I look at it, with an IEEE single at 2^24, then 1.0f is less than 1 LSB. So adding 1.0f to 16777216.0f does nothing -- you are trying to add less than 1 LSB, which obviously means you actually add 0. But my understanding of IEEE floating point numbers isn't very amazing so I might be thinking about it wrong... I just knew that would be the magic number to test the compiler.

Re: XC and long long, float, double and long double

Posted: Wed Mar 21, 2018 4:15 pm
by aclassifier
Hmm.. Would you say that "1.0" within the 23 bits ((2^24)-1) is "1.0" but from 0xffffff this as stated "1.0" is less than "1.0". So the semantics of "1.0" changes?

Of course it's a fraction of 1, so I guess 0xffffff is 0.999999999.. is interpreted as 1.00000000 == sign 0, exp 0, fraction 0xffffff. I guess this is another side of the two representations of zero?
Off Topic
Yes, I too have had to bang my head on floats. Some 25 years ago, but then I was using transputer occam REAL32 and REAL64. The transputer didn't have the bug that the pentium had (Pentium FDIV bug) and INMOS (in pre XMOS times) certainly bragged about it at the conferences! But I was vaccinated enough (for occam, against C!) that I still sit here having fun with XC (in post work times)