Jump to content
43oh

Faster printing of single precision floating point


Recommended Posts

Printf supports the %e, %f and %g format specifiers for printing floating point numbers. Due to the automatic type promotion of varadic functions in C, the printf code must always print double precision floating point. This makes printing single precision floating point numbers slower than optimal. The precision rounding done by printf also imposes a speed penalty. The code presented here will print single precision floating point numbers much faster than printf - up to 75 times faster. It allows the number of significant digits to be 3 to 8 (a maximum of 7 is recommended). The printed number will be normalized to the range to 1.0 to less than 1000.0 and the appropriate SI prefix appended. This is similar to what the printf %e format does (1.0 to less than 10.0), but a bit easier to interpret. The full range of single precision float can not be represented by SI prefixes, so very small and very large numbers will have '?' as the prefix. This code is intended for display only. It should not be used to store values in a file for later conversion back to float due to limitations in rounding and range.

 

A brief explanation of the code.

Do a bitwise conversion of the float to a 32 bit unsigned integer. This is done with by getting the address of the float, casting to an unsigned integer pointer, and then dereferencing the pointer. Simply casting to an unsigned integer would not produce a bitwise copy.

    uint32_t s = *(uint32_t *)&f;
The msb contains the sign flag. Append a '-' to the string if the floating point number is negative.

    if (s & (1UL << 31)) *a++ = '-';
Extract the 8 bit exponent.

    int e = (s >> 23) & 0xFF;
Move the significand to the upper 24 bits. Set the msb to 0.

    s <<= 8; s &= ~(1UL << 31);
An exponent of 255 is used for special values of NaN (not a number) and infinity. Handle these special cases and return.

    if (e == 255) {
        if (s) {
            strcpy(a, "NaN");
        } else {
            strcpy(a, "Inf");
        }
        return;
An exponent of 0 is used to represent a value of 0 and for denormals. A value of 0 is handled by setting the exponent to 127 - the same exponent used to represent 1.0, and leaving the significand as 0. Denormal numbers do not have the implicit msb of 1, so they are normalized by shifting until the leading 1 is in the msb position.

    } else if (e == 0) {
        if (s) {
            e = 1;
            while (!(s & (1UL << 31))) s <<= 1, --e;
        } else {
            e = 127;
        }
If the exponent is some other value, then set the msb of the significand.

    } else {
        s |= (1UL << 31);
    }
Setup a pointer to the SI prefix. This will be adjusted as the value is normalized.

    char const * sp = "???????yzafpnum kMGTPEZY????" + 15;
If the value is less than 1.0 it must be multiplied by 1000 until it is 1.0 or greater. Multiplication by 1000 is done by an implicit multiply by 1024 and then subtracting a multiply by 16 and a multiply by 8.

    if (e < 127) {
        do {
            s = s - (s >> 6) - (s >> 7);
            if (!(s & (1UL << 31))) s <<= 1, --e;
            e += 10;
            --sp;
        } while (e < 127);
If the value is 1000.0 or more it must be divided by 1000 until it is less than 1000.0. An unrolled floating point divide is used for maximum speed.

    } else if (e > 135) {
        while (e > (126 + 10) || (e == (126 + 10) && s >= (1000UL << (32 - 10)))) {
            uint32_t n = s;
            s = 0;
            uint32_t d = 1000UL << (32 - 10);
            if (n >= d) n -= d, s |= (1UL << 31); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 30); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 29); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 28); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 27); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 26); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 25); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 24); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 23); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 22); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 21); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 20); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 19); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 18); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 17); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 16); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 15); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 14); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 13); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 12); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 11); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 10); d >>= 1;
            if (n >= d) n -= d, s |= (1UL <<  9); d >>= 1;
            if (n >= d) n -= d, s |= (1UL <<  8); d >>= 1;
            if (n >= d) s += (1UL << 8);
            if (!(s & (1UL << 31))) s <<= 1, --e;
            e -= 9;
            ++sp;
        }
The divide code is quite time consuming, so it would be advantageous to quickly reduce very large numbers. A divide by 1,000,000,000,000 is used to improve performance for these large numbers.

The preceding multiply code could do the same for very small numbers, but there is no speed advantage due to the multiply by 1000 using 2 shift/subtract operations and multiply by lager values requiring more than 2 per 1000.

        while (e > (150 + 16) || (e == (150 + 16) && s > (999999995904ULL >> 16))) {
            uint64_t n = s;
            n <<= 32;
            s = 0;
            uint64_t d = 1000000000000ULL << (64 - 40);
            if (n >= d) n -= d, s |= (1UL << 31); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 30); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 29); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 28); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 27); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 26); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 25); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 24); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 23); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 22); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 21); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 20); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 19); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 18); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 17); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 16); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 15); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 14); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 13); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 12); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 11); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 10); d >>= 1;
            if (n >= d) n -= d, s |= (1UL <<  9); d >>= 1;
            if (n >= d) n -= d, s |= (1UL <<  8); //d >>= 1;
            //if (n >= d) s += (1UL << 8);
            if (n) s += (1UL << 8);
            if (!(s & (1UL << 31))) s <<= 1, --e;
            e -= 39;
            sp += 4;
        }
Rounding is the most difficult part of printing floating point numbers. Precalculated float constants are applied based on the value of the float and the specified number of significant digits. This simple method is fast and allows for good results for up to 7 significant digits.

typedef struct {
    uint32_t s;
    int e;
} TFR;

TFR const r[] = {
    0x800000UL << 7, 126 + 1,	// 0.5
    0xCCCCCDUL << 7, 122 + 1,	// 0.05
    0xA3D70AUL << 7, 119 + 1,	// 0.005
    0x83126FUL << 7, 116 + 1,	// 0.0005
    0xD1B717UL << 7, 112 + 1,	// 0.00005
    0xA7C5ACUL << 7, 109 + 1,	// 0.000005
    0x8637BDUL << 7, 106 + 1,	// 0.0000005
    0xD6BF95UL << 7, 102 + 1	// 0.00000005
};

    if (d < 3) d = 3; else if (d > 8) d = 8;
    if (s) {
        TFR const *pr = &r[d - 3];
        if (e < (126 + 4) || (e == (126  + 4) && s < (10UL << (32 - 4)))) {			// < 10
            pr += 2;
        } else if (e < (126 + 7) || (e == (126 + 7) && s < (100UL << (32 - 7)))) {	// < 100
            ++pr;
        }
        s += (pr->s >> (e - pr->e));
        if (e == (126 + 10) && s >= (1000UL << (32 - 10))) s = (1UL << 31), e = 127, ++sp;
        else if (!(s & (1UL << 31))) s >>= 1, s |= (1UL << 31), ++e;
    }
The integer part is printed using iterative subtraction of base 10 constants. This is typically faster than the common divide/modulus method.

    unsigned i = s >> 16;
    i >>= (136 - e);
    unsigned id = 1;
    char c;
    if (i >= (100 << 6)) {
        ++id; c = '0';
        while (i >= (100 << 6)) i -= (100 << 6), ++c;
        *a++ = c;
    }
    if (id == 2 || i >= (10 << 6)) {
        ++id; c = '0';
        while (i >= (10 << 6)) i -= (10 << 6), ++c;
        *a++ = c;
    }
    c = '0';
    while (i >= (1 << 6)) i -= (1 << 6), ++c;
    *a++ = c;
The fractional part is printed by iterative multiplication by 10.

    *a++ = '.';
    if (e < 130) s >>= (130 - e); else s <<= (e - 130);
    d -= id;
    while (d) {
        s &= ((1UL << 28) - 1);
        s = (s << 3) + (s << 1);
        *a++ = '0' + (s >> 28);
        --d;
    }
The SI prefix is appended and the string is terminated.

    *a++ = *sp;
    *a = 0;
The resulting performance increase was more than I expected.

 

           TI 4.4.4         GCC 4.9.1
---------------------------------------
%e       16402  6.47 s    non-functional
%f       16380  5.78 s    non-functional
%g       16402  4.69 s    non-functional
ftoas(7)  8480  0.12 s    11892  0.27 s
ftoas(3)  8480  0.09 s    11892  0.17 s
Results of the test code using ftoas(7), %e, %g, and %f

0.000000  0.000000e+00 0 0.000000
1.401298? 0.000000e+00 0 0.000000
1.401298? 0.000000e+00 0 0.000000
9.809089? 0.000000e+00 0 0.000000
99.49219? 0.000000e+00 0 0.000000
1.000527? 0.000000e+00 0 0.000000
9.999666? 0.000000e+00 0 0.000000
99.99946? 0.000000e+00 0 0.000000
1.000000? 0.000000e+00 0 0.000000
12.00000? 1.200000e-38 1.2e-38 0.000000
100.0000? 1.000000e-37 1e-37 0.000000
1.000000? 1.000000e-36 1e-36 0.000000
10.00000? 1.000000e-35 1e-35 0.000000
100.0000? 1.000000e-34 1e-34 0.000000
1.000000? 1.000000e-33 1e-33 0.000000
10.00000? 1.000000e-32 1e-32 0.000000
100.0000? 1.000000e-31 1e-31 0.000000
1.000000? 1.000000e-30 1e-30 0.000000
10.00000? 1.000000e-29 1e-29 0.000000
100.0000? 1.000000e-28 1e-28 0.000000
1.000000? 1.000000e-27 1e-27 0.000000
10.00000? 1.000000e-26 1e-26 0.000000
100.0000? 1.000000e-25 1e-25 0.000000
1.000000y 1.000000e-24 1e-24 0.000000
10.00000y 1.000000e-23 1e-23 0.000000
100.0000y 1.000000e-22 1e-22 0.000000
1.000000z 1.000000e-21 1e-21 0.000000
10.00000z 1.000000e-20 1e-20 0.000000
100.0000z 1.000000e-19 1e-19 0.000000
1.000000a 1.000000e-18 1e-18 0.000000
10.00000a 1.000000e-17 1e-17 0.000000
100.0000a 1.000000e-16 1e-16 0.000000
1.000000f 1.000000e-15 1e-15 0.000000
10.00000f 1.000000e-14 1e-14 0.000000
100.0000f 1.000000e-13 1e-13 0.000000
1.000000p 1.000000e-12 1e-12 0.000000
10.00000p 1.000000e-11 1e-11 0.000000
100.0000p 1.000000e-10 1e-10 0.000000
1.000000n 1.000000e-09 1e-09 0.000000
10.00000n 1.000000e-08 1e-08 0.000000
100.0000n 1.000000e-07 1e-07 0.000000
1.000000u 1.000000e-06 1e-06 0.000001
10.00000u 1.000000e-05 1e-05 0.000010
100.0000u 1.000000e-04 0.0001 0.000100
1.000000m 1.000000e-03 0.001 0.001000
10.00000m 1.000000e-02 0.01 0.010000
100.0000m 1.000000e-01 0.1 0.100000
1.000000  1.000000e+00 1 1.000000
1.234568  1.234568e+00 1.23457 1.234568
10.00000  1.000000e+01 10 10.000000
100.0000  1.000000e+02 100 100.000000
1.000000k 1.000000e+03 1000 1000.000000
10.00000k 1.000000e+04 10000 10000.000000
100.0000k 1.000000e+05 100000 100000.000000
1.000000M 1.000000e+06 1e+06 1000000.000000
10.00000M 1.000000e+07 1e+07 10000000.000000
100.0000M 1.000000e+08 1e+08 100000000.000000
1.000000G 1.000000e+09 1e+09 1000000000.000000
10.00000G 1.000000e+10 1e+10 10000000000.000000
100.0000G 1.000000e+11 1e+11 99999997952.000010
1.000000T 1.000000e+12 1e+12 999999995903.999925
10.00000T 1.000000e+13 1e+13 9999999827968.000174
100.0000T 1.000000e+14 1e+14 100000000376832.008362
1.000000P 1.000000e+15 1e+15 999999986991104.125977
10.00000P 1.000000e+16 1e+16 10000000272564222.812653
100.0000P 1.000000e+17 1e+17 99999998430674934.387207
1.000000E 1.000000e+18 1e+18 999999984306749343.872070
10.00000E 1.000000e+19 1e+19 9999999980506448745.727539
100.0000E 1.000000e+20 1e+20 100000002004087710380.554199
1.000000Z 1.000000e+21 1e+21 1000000020040877103805.541992
10.00000Z 1.000000e+22 1e+22 9999999778196308612823.486328
100.0000Z 1.000000e+23 1e+23 99999997781963086128234.863281
1.000000Y 1.000000e+24 1e+24 1000000013848427772521972.656250
10.00000Y 1.000000e+25 1e+25 9999999562023527622222900.390625
100.0000Y 1.000000e+26 1e+26 100000002537764322757720947.265625
1.000000? 1.000000e+27 1e+27 999999988484154701232910156.250000
10.00000? 9.999999e+27 1e+28 9999999442119691371917724609.375000
100.0000? 1.000000e+29 1e+29 100000001504746651649475097656.250000
1.000000? 1.000000e+30 1e+30 1000000015047466516494750976562.500000
10.00000? 1.000000e+31 1e+31 9999999848243210315704345703125.000000
100.0000? 1.000000e+32 1e+32 100000003318135333061218261718750.000000
1.000000? 1.000000e+33 1e+33 999999994495727896690368652343750.000000
10.00000? 1.000000e+34 1e+34 9999999790214771032333374023437500.000000
100.0000? 1.000000e+35 1e+35 100000004091847860813140869140625000.000000
1.000000? 1.000000e+36 1e+36 999999961690316438674926757812500000.000000
10.00000? 1.000000e+37 1e+37 9999999933815813064575195312500000000.000000
100.0000? 1.000000e+38 1e+38 99999996802856898307800292968750000000.000000
340.0001? 3.400000e+38 3.4e+38 339999995214436411857604980468750000000.000000
NaN nan nan nan
Inf +inf +inf +inf
Complete code with test case.

#include <msp430.h> 
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <math.h>

static void print(char const *s)
{
    while(*s) {
        while(!(UCA1IFG & UCTXIFG));
        UCA1TXBUF = *s++;
    }
}

typedef struct {
    uint32_t s;
    int e;
} TFR;

TFR const r[] = {
    0x800000UL << 7, 126 + 1,	// 0.5
    0xCCCCCDUL << 7, 122 + 1,	// 0.05
    0xA3D70AUL << 7, 119 + 1,	// 0.005
    0x83126FUL << 7, 116 + 1,	// 0.0005
    0xD1B717UL << 7, 112 + 1,	// 0.00005
    0xA7C5ACUL << 7, 109 + 1,	// 0.000005
    0x8637BDUL << 7, 106 + 1,	// 0.0000005
    0xD6BF95UL << 7, 102 + 1	// 0.00000005
};

void ftoas(char *a, float const f, unsigned d)
{
    uint32_t s = *(uint32_t *)&f;
    if (s & (1UL << 31)) *a++ = '-';
    int e = (s >> 23) & 0xFF;
    s <<= 8; s &= ~(1UL << 31);

    if (e == 255) {
        if (s) {
            strcpy(a, "NaN");
        } else {
            strcpy(a, "Inf");
        }
        return;
    } else if (e == 0) {
        if (s) {
            e = 1;
            while (!(s & (1UL << 31))) s <<= 1, --e;
        } else {
            e = 127;
        }
    } else {
        s |= (1UL << 31);
    }

    char const * sp = "???????yzafpnum kMGTPEZY????" + 15;
    if (e < 127) {
        do {
            s = s - (s >> 6) - (s >> 7);
            if (!(s & (1UL << 31))) s <<= 1, --e;
            e += 10;
            --sp;
        } while (e < 127);
    } else if (e > 135) {
        while (e > (150 + 16) || (e == (150 + 16) && s > (999999995904ULL >> 16))) {
            uint64_t n = s;
            n <<= 32;
            s = 0;
            uint64_t d = 1000000000000ULL << (64 - 40);
            if (n >= d) n -= d, s |= (1UL << 31); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 30); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 29); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 28); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 27); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 26); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 25); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 24); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 23); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 22); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 21); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 20); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 19); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 18); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 17); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 16); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 15); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 14); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 13); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 12); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 11); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 10); d >>= 1;
            if (n >= d) n -= d, s |= (1UL <<  9); d >>= 1;
            if (n >= d) n -= d, s |= (1UL <<  8); //d >>= 1;
            //if (n >= d) s += (1UL << 8);
            if (n) s += (1UL << 8);
            if (!(s & (1UL << 31))) s <<= 1, --e;
            e -= 39;
            sp += 4;
        }
        while (e > (126 + 10) || (e == (126 + 10) && s >= (1000UL << (32 - 10)))) {
            uint32_t n = s;
            s = 0;
            uint32_t d = 1000UL << (32 - 10);
            if (n >= d) n -= d, s |= (1UL << 31); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 30); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 29); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 28); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 27); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 26); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 25); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 24); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 23); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 22); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 21); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 20); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 19); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 18); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 17); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 16); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 15); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 14); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 13); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 12); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 11); d >>= 1;
            if (n >= d) n -= d, s |= (1UL << 10); d >>= 1;
            if (n >= d) n -= d, s |= (1UL <<  9); d >>= 1;
            if (n >= d) n -= d, s |= (1UL <<  8); d >>= 1;
            if (n >= d) s += (1UL << 8);
            if (!(s & (1UL << 31))) s <<= 1, --e;
            e -= 9;
            ++sp;
        }
    }

    if (d < 3) d = 3; else if (d > 8) d = 8;
    if (s) {
        TFR const *pr = &r[d - 3];
        if (e < (126 + 4) || (e == (126  + 4) && s < (10UL << (32 - 4)))) {        // < 10
            pr += 2;
        } else if (e < (126 + 7) || (e == (126 + 7) && s < (100UL << (32 - 7)))) { // < 100
            ++pr;
        }
        s += (pr->s >> (e - pr->e));
        if (e == (126 + 10) && s >= (1000UL << (32 - 10))) s = (1UL << 31), e = 127, ++sp;
        else if (!(s & (1UL << 31))) s >>= 1, s |= (1UL << 31), ++e;
    }

    unsigned i = s >> 16;
    i >>= (136 - e);
    unsigned id = 1;
    char c;
    if (i >= (100 << 6)) {
        ++id; c = '0';
        while (i >= (100 << 6)) i -= (100 << 6), ++c;
        *a++ = c;
    }
    if (id == 2 || i >= (10 << 6)) {
        ++id; c = '0';
        while (i >= (10 << 6)) i -= (10 << 6), ++c;
        *a++ = c;
    }
    c = '0';
    while (i >= (1 << 6)) i -= (1 << 6), ++c;
    *a++ = c;

    *a++ = '.';

    if (e < 130) s >>= (130 - e); else s <<= (e - 130);

    d -= id;
    while (d) {
        s &= ((1UL << 28) - 1);
        s = (s << 3) + (s << 1);
        *a++ = '0' + (s >> 28);
        --d;
    }

    *a++ = *sp;
    *a = 0;
}


#define smclk_freq  (32768UL * 31UL)            // SMCLK frequency in hertz
#define bps         (9600UL)                    // Async serial bit rate

int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;                   // Stop watchdog timer
                                                //
    P4SEL = BIT4 | BIT5;                        // Enable UART pins
    P4DIR = BIT4 | BIT5;                        //
                                                //
                                                // Initialize UART
    UCA1CTL1 = UCSWRST;                         // Hold USCI in reset to allow configuration
    UCA1CTL0 = 0;                               // No parity, LSB first, 8 bits, one stop bit, UART (async)
    const unsigned long brd = (smclk_freq + (bps >> 1)) / bps;  // Bit rate divisor
    UCA1BR1 = (brd >> 12) & 0xFF;               // High byte of whole divisor
    UCA1BR0 = (brd >> 4) & 0xFF;                // Low byte of whole divisor
    UCA1MCTL = ((brd << 4) & 0xF0) | UCOS16;    // Fractional divisor, oversampling mode
    UCA1CTL1 = UCSSEL_2;                        // Use SMCLK for bit rate generator, release reset
    
    char s[32], t[96];

    float const tv[] = {
        0.0f,
        7.1e-46f,
        1.0e-45f,
        1.0e-44f,
        1.0e-43f,
        1.0e-42f,
        1.0e-41f,
        1.0e-40f,
        1.0e-39f,
        1.2e-38f,
        1.0e-37f,
        1.0e-36f,
        1.0e-35f,
        1.0e-34f,
        1.0e-33f,
        1.0e-32f,
        1.0e-31f,
        1.0e-30f,
        1.0e-29f,
        1.0e-28f,
        1.0e-27f,
        1.0e-26f,
        1.0e-25f,
        1.0e-24f,
        1.0e-23f,
        1.0e-22f,
        1.0e-21f,
        1.0e-20f,
        1.0e-19f,
        1.0e-18f,
        1.0e-17f,
        1.0e-16f,
        1.0e-15f,
        1.0e-14f,
        1.0e-13f,
        1.0e-12f,
        1.0e-11f,
        1.0e-10f,
        1.0e-9f,
        1.0e-8f,
        1.0e-7f,
        0.000001f,
        0.00001f,
        0.0001f,
        0.001f,
        0.01f,
        0.1f,
        1.0f,
        1.23456789f,
        10.0f,
        100.0f,
        1000.0f,
        10000.0f,
        100000.0f,
        1000000.0f,
        10000000.0f,
        100000000.0f,
        1000000000.0f,
        1.0e10f,
        1.0e11f,
        1.0e12f,
        1.0e13f,
        1.0e14f,
        1.0e15f,
        1.0e16f,
        1.0e17f,
        1.0e18f,
        1.0e19f,
        1.0e20f,
        1.0e21f,
        1.0e22f,
        1.0e23f,
        1.0e24f,
        1.0e25f,
        1.0e26f,
        1.0e27f,
        1.0e28f,
        1.0e29f,
        1.0e30f,
        1.0e31f,
        1.0e32f,
        1.0e33f,
        1.0e34f,
        1.0e35f,
        1.0e36f,
        1.0e37f,
        1.0e38f,
        3.4e38f,
        NAN,
        INFINITY
    };

    TA0EX0 = 7;
    TA0CTL = TASSEL_2 | ID_3 | MC_2;
    TA0CTL |= TACLR;

    unsigned i;
    for (i = 0; i < sizeof(tv) / sizeof(tv[0]); ++i) {
        float const f = tv[i];
        ftoas(s, f, 7);
        //print(s); print("\r\n");
        //sprintf(t, "%e", f);
        //sprintf(t, "%f", f);
        //sprintf(t, "%g", f);
        //sprintf(t, "%e %f %g %s\r\n", f, f, f, s);
        sprintf(t, "%s %e %g %f\r\n", s, f, f, f);
        print(t);
    }

    volatile float et = ((float)TA0R + ((TA0CTL & TAIFG) ? 65536.0 : 0.0)) * 63.0f / 1000000.0f; // Elapsed time in microseconds
    ftoas(t, et, 5);
    //sprintf(t, "%f", et);
    print(t); print("s\r\n");

    for(;;

    return 0;
}
Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...