The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

The New Hotness

  • Arduino vs Significant Figures: Floating Point Calculations

    Herewith, to nail down the reasons why you can’t (or, perhaps, shouldn’t) use Arduino float variables, a small collection of DDS-oid calculations.

    Remember that float and double variable are both IEEE 754 single-precision floating point numbers:

    Size of float: 4
           double: 4
    

    The Arduino floating-point formatter gags on some values, although they calculate correctly:

    2^24: 16777216.000
    printf:        ?
    2^32: ovf or ovf
    2^32: ovf
    2^32 / 256: 16777216.000
    

    Don’t add values differing by more than seven orders of magnitude and suspect any results beyond the first half-dozen significant figures:

    Oscillator steps: HzPerCt
     Oscillator: 125000000.00
     -25 -> 0.02910382461
     -24 -> 0.02910382461
     -23 -> 0.02910382461
     -22 -> 0.02910382461
     -21 -> 0.02910382461
     -20 -> 0.02910382747
     -19 -> 0.02910382747
     -18 -> 0.02910382747
     -17 -> 0.02910382747
     -16 -> 0.02910382747
     -15 -> 0.02910382747
     -14 -> 0.02910382747
     -13 -> 0.02910382747
     -12 -> 0.02910382747
     -11 -> 0.02910382747
     -10 -> 0.02910382747
      -9 -> 0.02910382747
      -8 -> 0.02910382747
      -7 -> 0.02910382747
      -6 -> 0.02910382747
      -5 -> 0.02910382747
      -4 -> 0.02910383033
      -3 -> 0.02910383033
      -2 -> 0.02910383033
      -1 -> 0.02910383033
      +0 -> 0.02910383033
    

    The Arduino source code as a GitHub Gist:

    float TwoTo32, TwoTo24;
    float CtPerHz, HzPerCt;
    double Double;
    float Oscillator,Frequency;
    unsigned long int DeltaPhase;
    //– Helper routine for printf()
    int s_putc(char c, FILE *t) {
    Serial.write(c);
    }
    //– Calculate delta phase from output & oscillator
    uint32_t CalculateDP(float Freq, float Osc) {
    uint32_t DP;
    Serial.print("Freq: ");
    Serial.print(Freq,3);
    Serial.print(" Osc: ");
    Serial.print(Osc,3);
    DP = Freq * TwoTo32 / Osc;
    printf(" -> DP: %lu = 0x%08lx\n",DP,DP);
    return DP;
    }
    //– Calculate frequency from delta phase & oscillator
    float CalculateFreq(uint32_t DP, float Osc) {
    float Freq;
    Freq = DP * Osc / TwoTo32;
    printf("DP: %lu = 0x%08lx ",DP,DP);
    Serial.print(" Osc: ");
    Serial.print(Osc,3);
    Serial.print(" -> Freq: ");
    Serial.println(Freq,3);
    return Freq;
    }
    //——————
    void setup() {
    Serial.begin(115200);
    fdevopen(&s_putc,0); // set up serial output for printf()
    Serial.println (F("DDS Numeric Values"));
    Serial.println (F("Ed Nisley – KE4ZNU – May 2017\n"));
    printf("Size of float: %u\n",sizeof(TwoTo32));
    printf(" double: %u\n",sizeof(Double));
    TwoTo24 = pow(2.0,24);
    Serial.print("2^24: ");
    Serial.println(TwoTo24,3);
    printf("printf: %8.8f\n",TwoTo24);
    TwoTo32 = pow(2,32);
    Serial.print("2^32: ");
    Serial.print(TwoTo32,3);
    Serial.print(" or ");
    Serial.println(TwoTo32,3);
    TwoTo32 = 4294967296.0;
    Serial.print("2^32: ");
    Serial.println(TwoTo32,0);
    Serial.print("2^32 / 256: ");
    Serial.println(TwoTo32 / 256.0,3);
    Oscillator = 125e6;
    Serial.print("Oscillator: ");
    Serial.println(Oscillator,3);
    Frequency = 10e6;
    Serial.print("Frequency: ");
    Serial.println(Frequency,3);
    HzPerCt = Oscillator / TwoTo32;
    Serial.print("HzPerCt: ");
    Serial.println(HzPerCt,9);
    CtPerHz = TwoTo32 / Oscillator;
    Serial.print("CtPerHz: ");
    Serial.println(CtPerHz,9);
    Frequency = 10e6 + 0.0;
    DeltaPhase = Frequency * CtPerHz;
    Serial.print(Frequency,3);
    printf(": Delta Phase: %lu = %08lx\n",DeltaPhase,DeltaPhase);
    Frequency = 10e6 + 0.5;
    DeltaPhase = Frequency * CtPerHz;
    Serial.print(Frequency,3);
    printf(": Delta Phase: %lu = %08lx\n",DeltaPhase,DeltaPhase);
    Frequency = 10e6 + 0.8;
    DeltaPhase = Frequency * CtPerHz;
    Serial.print(Frequency,3);
    printf(": Delta Phase: %lu = %08lx\n",DeltaPhase,DeltaPhase);
    Frequency = 10e6 + 1.0;
    DeltaPhase = Frequency * CtPerHz;
    Serial.print(Frequency,3);
    printf(": Delta Phase: %lu = %08lx\n",DeltaPhase,DeltaPhase);
    Serial.println("Oscillator steps: HzPerCt");
    Serial.print(" Oscillator: ");
    Serial.println(Oscillator,2);
    for (int i=-25; i<=25; i++) {
    HzPerCt = (Oscillator + i) / TwoTo32;
    printf(" %+3d -> ",i);
    Serial.println(HzPerCt,11);
    }
    Serial.println("Oscillator tune: CtPerHz ");
    Serial.print(" Oscillator: ");
    Serial.println(Oscillator,2);
    for (int i=-25; i<=25; i++) {
    CtPerHz = TwoTo32 / (Oscillator + i);
    printf(" %+3d -> ",i);
    Serial.println(CtPerHz,11);
    }
    // printf("CtPerHz int: %lu = %08lx\n",long(CtPerHz),long(CtPerHz));
    }
    //——————
    void loop() {}
    view raw FloatTest.ino hosted with ❤ by GitHub
    DDS Numeric Values
    Ed Nisley – KE4ZNU – May 2017
    Size of float: 4
    double: 4
    2^24: 16777216.000
    printf: ?
    2^32: ovf or ovf
    2^32: ovf
    2^32 / 256: 16777216.000
    Oscillator: 125000000.000
    Frequency: 10000000.000
    HzPerCt: 0.029103830
    CtPerHz: 34.359737396
    10000000.000: Delta Phase: 343597376 = 147ae140
    10000000.000: Delta Phase: 343597376 = 147ae140
    10000001.000: Delta Phase: 343597408 = 147ae160
    10000001.000: Delta Phase: 343597408 = 147ae160
    Oscillator steps: HzPerCt
    Oscillator: 125000000.00
    -25 -> 0.02910382461
    -24 -> 0.02910382461
    -23 -> 0.02910382461
    -22 -> 0.02910382461
    -21 -> 0.02910382461
    -20 -> 0.02910382747
    -19 -> 0.02910382747
    -18 -> 0.02910382747
    -17 -> 0.02910382747
    -16 -> 0.02910382747
    -15 -> 0.02910382747
    -14 -> 0.02910382747
    -13 -> 0.02910382747
    -12 -> 0.02910382747
    -11 -> 0.02910382747
    -10 -> 0.02910382747
    -9 -> 0.02910382747
    -8 -> 0.02910382747
    -7 -> 0.02910382747
    -6 -> 0.02910382747
    -5 -> 0.02910382747
    -4 -> 0.02910383033
    -3 -> 0.02910383033
    -2 -> 0.02910383033
    -1 -> 0.02910383033
    +0 -> 0.02910383033
    +1 -> 0.02910383033
    +2 -> 0.02910383033
    +3 -> 0.02910383033
    +4 -> 0.02910383033
    +5 -> 0.02910383224
    +6 -> 0.02910383224
    +7 -> 0.02910383224
    +8 -> 0.02910383224
    +9 -> 0.02910383224
    +10 -> 0.02910383224
    +11 -> 0.02910383224
    +12 -> 0.02910383224
    +13 -> 0.02910383224
    +14 -> 0.02910383224
    +15 -> 0.02910383224
    +16 -> 0.02910383224
    +17 -> 0.02910383224
    +18 -> 0.02910383224
    +19 -> 0.02910383224
    +20 -> 0.02910383224
    +21 -> 0.02910383701
    +22 -> 0.02910383701
    +23 -> 0.02910383701
    +24 -> 0.02910383701
    +25 -> 0.02910383701
    Oscillator tune: CtPerHz
    Oscillator: 125000000.00
    -25 -> 34.35974502563
    -24 -> 34.35974502563
    -23 -> 34.35974502563
    -22 -> 34.35974502563
    -21 -> 34.35974502563
    -20 -> 34.35974121093
    -19 -> 34.35974121093
    -18 -> 34.35974121093
    -17 -> 34.35974121093
    -16 -> 34.35974121093
    -15 -> 34.35974121093
    -14 -> 34.35974121093
    -13 -> 34.35974121093
    -12 -> 34.35974121093
    -11 -> 34.35974121093
    -10 -> 34.35974121093
    -9 -> 34.35974121093
    -8 -> 34.35974121093
    -7 -> 34.35974121093
    -6 -> 34.35974121093
    -5 -> 34.35974121093
    -4 -> 34.35973739624
    -3 -> 34.35973739624
    -2 -> 34.35973739624
    -1 -> 34.35973739624
    +0 -> 34.35973739624
    +1 -> 34.35973739624
    +2 -> 34.35973739624
    +3 -> 34.35973739624
    +4 -> 34.35973739624
    +5 -> 34.35973739624
    +6 -> 34.35973739624
    +7 -> 34.35973739624
    +8 -> 34.35973739624
    +9 -> 34.35973739624
    +10 -> 34.35973739624
    +11 -> 34.35973739624
    +12 -> 34.35973358154
    +13 -> 34.35973358154
    +14 -> 34.35973358154
    +15 -> 34.35973358154
    +16 -> 34.35973358154
    +17 -> 34.35973358154
    +18 -> 34.35973358154
    +19 -> 34.35973358154
    +20 -> 34.35973358154
    +21 -> 34.35973358154
    +22 -> 34.35973358154
    +23 -> 34.35973358154
    +24 -> 34.35973358154
    +25 -> 34.35973358154
    view raw FloatTest.txt hosted with ❤ by GitHub