XC and long long, float, double and long double Topic is solved

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
aclassifier
Respected Member
Posts: 507
Joined: Wed Apr 25, 2012 8:52 pm

XC and long long, float, double and long double

Post 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?
Last edited by aclassifier on Wed Mar 21, 2018 2:55 pm, edited 1 time in total.
--
Øyvind Teig
Trondheim (Norway)
https://www.teigfam.net/oyvind/home/
View Solution
User avatar
akp
XCore Expert
Posts: 580
Joined: Thu Nov 26, 2015 11:47 pm

Post 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);
User avatar
akp
XCore Expert
Posts: 580
Joined: Thu Nov 26, 2015 11:47 pm

Post 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;
    }
User avatar
aclassifier
Respected Member
Posts: 507
Joined: Wed Apr 25, 2012 8:52 pm

Post 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
--
Øyvind Teig
Trondheim (Norway)
https://www.teigfam.net/oyvind/home/
User avatar
akp
XCore Expert
Posts: 580
Joined: Thu Nov 26, 2015 11:47 pm

Post 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.
User avatar
aclassifier
Respected Member
Posts: 507
Joined: Wed Apr 25, 2012 8:52 pm

Post 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)
--
Øyvind Teig
Trondheim (Norway)
https://www.teigfam.net/oyvind/home/