From 87fd0665ec722b4d514c79c37482b8e9aec5ace9 Mon Sep 17 00:00:00 2001 From: rob tillaart Date: Fri, 5 Nov 2021 17:24:10 +0100 Subject: [PATCH] 0.2.2 IEEE754tools --- libraries/IEEE754tools/.arduino-ci.yml | 10 +- .../.github/workflows/arduino_test_runner.yml | 10 +- libraries/IEEE754tools/IEEE754tools.h | 87 ++++++-- .../examples/FastNegate/FastNegate.ino | 58 ++++-- .../examples/IEEE754_equal/IEEE754_equal.ino | 194 ++++++++++++++++++ .../examples/float2double/float2double.ino | 28 ++- libraries/IEEE754tools/library.json | 2 +- libraries/IEEE754tools/library.properties | 2 +- libraries/IEEE754tools/readme.md | 43 +++- libraries/IEEE754tools/test/unit_test_001.cpp | 2 +- 10 files changed, 369 insertions(+), 67 deletions(-) create mode 100644 libraries/IEEE754tools/examples/IEEE754_equal/IEEE754_equal.ino diff --git a/libraries/IEEE754tools/.arduino-ci.yml b/libraries/IEEE754tools/.arduino-ci.yml index ff5659b9..cecf5850 100644 --- a/libraries/IEEE754tools/.arduino-ci.yml +++ b/libraries/IEEE754tools/.arduino-ci.yml @@ -2,6 +2,10 @@ compile: # Choosing to run compilation tests on 2 different Arduino platforms platforms: - uno - - leonardo - - due - - zero + # - due + # - zero + # - leonardo + - m4 + - esp32 + # - esp8266 + # - mega2560 diff --git a/libraries/IEEE754tools/.github/workflows/arduino_test_runner.yml b/libraries/IEEE754tools/.github/workflows/arduino_test_runner.yml index 476456bb..096b975b 100644 --- a/libraries/IEEE754tools/.github/workflows/arduino_test_runner.yml +++ b/libraries/IEEE754tools/.github/workflows/arduino_test_runner.yml @@ -4,10 +4,14 @@ name: Arduino CI on: [push, pull_request] jobs: - arduino_ci: + runTest: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: Arduino-CI/action@master - # Arduino-CI/action@v0.1.1 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 2.6 + - run: | + gem install arduino_ci + arduino_ci.rb diff --git a/libraries/IEEE754tools/IEEE754tools.h b/libraries/IEEE754tools/IEEE754tools.h index 530298a9..ffa12b69 100644 --- a/libraries/IEEE754tools/IEEE754tools.h +++ b/libraries/IEEE754tools/IEEE754tools.h @@ -2,7 +2,7 @@ // // FILE: IEEE754tools.h // AUTHOR: Rob Tillaart -// VERSION: 0.2.1 +// VERSION: 0.2.2 // PURPOSE: manipulate IEEE754 float numbers fast // URL: https://github.com/RobTillaart/IEEE754tools.git // @@ -15,10 +15,14 @@ // 0.1.03 2013-09-10 renamed IEEE_Sign IEEE_Exponent // 0.2.0 2020-06-30 own repo + some refactor... // 0.2.1 2020-12-30 arduino-CI +// 0.2.2 2021-11-05 update Arduino-CI, badges, readme.md +// some testing on ESP32 (no fixing) + #include "Arduino.h" -#define IEEE754_VERSION "0.2.1" +#define IEEE754_VERSION (F("0.2.2")) + // (un)comment lines to configure functionality / size //#define IEEE754_ENABLE_MSB // +78 bytes @@ -32,6 +36,7 @@ struct IEEEfloat uint8_t s:1; }; + // IEEE754 double layout; struct IEEEdouble { @@ -40,6 +45,7 @@ struct IEEEdouble uint8_t s:1; }; + // Arduino UNO double layout: // the UNO has no 64 bit double, it is only able to map 23 bits of the mantisse // a filler is added for the remaining bits. These might be useful in future? @@ -51,6 +57,7 @@ struct _DBL uint8_t s:1; }; + // for packing and unpacking a float union _FLOATCONV { @@ -59,6 +66,7 @@ union _FLOATCONV byte b[4]; }; + // for packing and unpacking a double union _DBLCONV { @@ -87,6 +95,7 @@ void dumpFloat(float number) // Serial.print(" mant: "); Serial.println(x->m); } + // print "double" components void dumpDBL(struct _DBL dbl) { @@ -97,12 +106,13 @@ void dumpDBL(struct _DBL dbl) Serial.println(dbl.m, HEX); } + // // mapping to/from 64bit double - best effort // // converts a float to a packed array of 8 bytes representing a 64 bit double -// restriction exponent and mantisse. +// restriction exponent and mantissa. // float; array of 8 bytes; LSBFIRST; MSBFIRST void float2DoublePacked(float number, byte* bar, int byteOrder = LSBFIRST) { @@ -134,9 +144,10 @@ void float2DoublePacked(float number, byte* bar, int byteOrder = LSBFIRST) #endif } + // converts a packed array of bytes into a 32bit float. // there can be an exponent overflow -// the mantisse is truncated to 23 bits. +// the mantissa is truncated to 23 bits. float doublePacked2Float(byte* bar, int byteOrder = LSBFIRST) { _FLOATCONV fl; @@ -174,6 +185,7 @@ float doublePacked2Float(byte* bar, int byteOrder = LSBFIRST) // return (fl.p.s) ? -INFINITY : INFINITY; } + // // TEST FUNCTIONS // @@ -185,6 +197,7 @@ int IEEE_NAN(float number) return ((*x) == 0x7FC0); } + // ~3.4x faster int IEEE_INF(float number) { @@ -195,7 +208,8 @@ int IEEE_INF(float number) return 0; } -// for the real speed freaks, the next two + +// for the real speed freaks, the next boolean IEEE_PosINF(float number) { return (* ((uint16_t*) &number + 1) ) == 0x7F80; @@ -207,8 +221,6 @@ boolean IEEE_NegINF(float number) } - - // // PROPERTIES // @@ -230,10 +242,12 @@ uint32_t IEEE_Mantisse(float number) return x->m; } + // // MATH FUNCTIONS // +// f = f * 2^n // factor ~2.7; (tested with *16) more correct than the faster one float IEEE_POW2(float number, int n) { @@ -248,6 +262,7 @@ float IEEE_POW2(float number, int n) return (fl.p.s) ? -INFINITY : INFINITY; } + // WARNING no overflow detection in the SHIFT (factor ~3.5) float IEEE_POW2fast(float number, int n) { @@ -258,7 +273,45 @@ float IEEE_POW2fast(float number, int n) } +// - FAILS ON ESP32 (x16 => x256 strange) +float IEEE_FLOAT_POW2fast(float number, int n) +{ + IEEEfloat* x = (IEEEfloat*) ((void*)&number); + x->e += n; + return number; +} + +// - NOT FASTER +// - FAILS ON ESP32 (==> divides by 4) +float IEEE_FLOAT_DIV2(float number) +{ + IEEEfloat* x = (IEEEfloat*) ((void*)&number); + x->e--; + return number; +} + + +bool IEEE_FLOAT_EQ(float &f, float &g) +{ + uint16_t *p = (uint16_t *) &f; + uint16_t *q = (uint16_t *) &g; + + return (*p++ == *q++) && (*p++ == *q++); +} + +bool IEEE_FLOAT_NEQ(float &f, float &g) +{ + uint16_t *p = (uint16_t *) &f; + uint16_t *q = (uint16_t *) &g; + + return (*p++ != *q++) || (*p++ != *q++); +} + + + + +//////////////////////////////////////////////////////////////////////////////// // // NOT TESTED FUNCTIONS // @@ -328,14 +381,17 @@ float IEEE_FLIP(float number) // x = *(((byte*) &number)+3) & 0x7F; // x = fabs(number); // GAIN = factor 2 + // *(((byte*) &number)+3) |= 0x80; // number == -fabs(number); // x = *(((byte*) &number)+3) | 0x80; // x == -fabs(number); // GAIN = factor 2 + // *(((byte*) &number)+3) ^= 0x80; // number = -number; // x = *(((byte*) &number)+3) ^ 0x80; // x = -number; // GAIN = factor 2 + // s = *(((uint8_t*) &number)+3) & 0x80; // s = sign(number); // if ( *(((byte*) &number)+3) & 0x80) x=2; // if (number < 0) x=2; // GAIN = factor 5 @@ -348,12 +404,6 @@ boolean IEEE_ZERO(float number) return (* ((uint32_t*) &number) ) & 0x7FFFFFFF; } -float IEEE_DIV2(float number) -{ - IEEEfloat* x = (IEEEfloat*) ((void*)&number); - x->e--; - return number; -} bool IEEE_LESS(float f, float g) { @@ -367,13 +417,16 @@ bool IEEE_LESS(float f, float g) return 0; } -bool IEEE_EQ(float f, float g) +bool IEEE_FLOAT_EQ(float &f, float &g) { - IEEEfloat* x = (IEEEfloat*) ((void*)&f); - IEEEfloat* y = (IEEEfloat*) ((void*)&g); - return (x->m == y->m) && (x->e == y->e) && (x->s != y->s); + not fast enough + return (memcmp(&f, &g, 4) == 0); + return (* ((uint32_t *) &f) - * ((uint32_t *) &g)) == 0 ; } */ + + // -- END OF FILE -- + diff --git a/libraries/IEEE754tools/examples/FastNegate/FastNegate.ino b/libraries/IEEE754tools/examples/FastNegate/FastNegate.ino index 52be2910..472b4458 100644 --- a/libraries/IEEE754tools/examples/FastNegate/FastNegate.ino +++ b/libraries/IEEE754tools/examples/FastNegate/FastNegate.ino @@ -31,14 +31,16 @@ void setup() void test_negfabs() { Serial.println(__FUNCTION__); - Serial.println("zz = -fabs(zz)"); + Serial.println("TEST : zz = -fabs(zz)"); start = micros(); for (int i = 0; i < 30000; i++) { *(((byte*) &zz) + 3) |= 0x80; // Force negative == -fabs(zz); } duration1 = micros() - start; - Serial.println(duration1 / 30000.0); + Serial.print("TIME : "); + Serial.println(duration1 / 30000.0, 4); + Serial.print("VALUE: "); Serial.println(zz); delay(10); @@ -49,10 +51,12 @@ void test_negfabs() zz = -fabs(zz); } duration2 = micros() - start; - Serial.println(duration2 / 30000.0); - Serial.print("Gain:\t"); - Serial.println(1.0 * duration2 / duration1); + Serial.print("TIME : "); + Serial.println(duration2 / 30000.0, 4); + Serial.print("VALUE: "); Serial.println(zz); + Serial.print("GAIN : "); + Serial.println(1.0 * duration2 / duration1, 2); Serial.println(); delay(10); } @@ -60,14 +64,16 @@ void test_negfabs() void test_fabs() { Serial.println(__FUNCTION__); - Serial.println("zz = fabs(zz)"); + Serial.println("TEST : zz = fabs(zz)"); start = micros(); for (int i = 0; i < 30000; i++) { *(((byte*) &zz) + 3) &= 0x7F; // force positive == fabs(zz); } duration1 = micros() - start; - Serial.println(duration1 / 30000.0); + Serial.print("TIME : "); + Serial.println(duration1 / 30000.0, 4); + Serial.print("VALUE: "); Serial.println(zz); delay(10); @@ -77,10 +83,12 @@ void test_fabs() zz = fabs(zz); } duration2 = micros() - start; - Serial.println(duration2 / 30000.0); - Serial.print("Gain:\t"); - Serial.println(1.0 * duration2 / duration1); + Serial.print("TIME : "); + Serial.println(duration2 / 30000.0, 4); + Serial.print("VALUE: "); Serial.println(zz); + Serial.print("GAIN : "); + Serial.println(1.0 * duration2 / duration1, 2); Serial.println(); delay(10); } @@ -88,14 +96,16 @@ void test_fabs() void test_negate() { Serial.println(__FUNCTION__); - Serial.println("zz = -zz"); + Serial.println("TEST : zz = -zz"); start = micros(); for (int i = 0; i < 30000; i++) { *(((byte*) &zz) + 3) ^= 0x80; } duration1 = micros() - start; - Serial.println(duration1 / 30000.0); + Serial.print("TIME : "); + Serial.println(duration1 / 30000.0, 4); + Serial.print("VALUE: "); Serial.println(zz); start = micros(); @@ -104,10 +114,12 @@ void test_negate() zz = -zz; } duration2 = micros() - start; - Serial.println(duration2 / 30000.0); - Serial.print("Gain:\t"); - Serial.println(1.0 * duration2 / duration1); + Serial.print("TIME : "); + Serial.println(duration2 / 30000.0, 4); + Serial.print("VALUE: "); Serial.println(zz); + Serial.print("GAIN : "); + Serial.println(1.0 * duration2 / duration1, 2); Serial.println(); delay(10); } @@ -115,14 +127,16 @@ void test_negate() void test_less_zero() { Serial.println(__FUNCTION__); - Serial.println("if (zz < 0) "); + Serial.println("TEST : if (zz < 0) "); start = micros(); for (int i = 0; i < 30000; i++) { if ( *(((byte*) &zz) + 3) & 0x80) x = 2; // equals if (zz < 0); } duration1 = micros() - start; - Serial.println(duration1 / 30000.0); + Serial.print("TIME : "); + Serial.println(duration1 / 30000.0, 4); + Serial.print("VALUE: "); Serial.println(zz); start = micros(); @@ -131,18 +145,20 @@ void test_less_zero() if (zz < 0) x = 2; } duration2 = micros() - start; - Serial.println(duration2 / 30000.0); - Serial.print("Gain:\t"); - Serial.println(1.0 * duration2 / duration1); + Serial.print("TIME : "); + Serial.println(duration2 / 30000.0, 4); + Serial.print("VALUE: "); Serial.println(zz); + Serial.print("GAIN : "); + Serial.println(1.0 * duration2 / duration1, 2); start = micros(); for (int i = 0; i < 30000; i++) { x = 2; } + Serial.print("TIME : "); Serial.println((micros() - start) / 30000.0, 4); - Serial.println(zz); Serial.println(); delay(10); } diff --git a/libraries/IEEE754tools/examples/IEEE754_equal/IEEE754_equal.ino b/libraries/IEEE754tools/examples/IEEE754_equal/IEEE754_equal.ino new file mode 100644 index 00000000..4bf181d7 --- /dev/null +++ b/libraries/IEEE754tools/examples/IEEE754_equal/IEEE754_equal.ino @@ -0,0 +1,194 @@ + +// +// FILE: // +// FILE: IEEE754_equal.ino +// AUTHOR: Rob Tillaart +// VERSION: 0.1.0 +// PURPOSE: experimental +// + +// NOTE +// - WORKS ON AVR +// - FAILS FOR ESP32 + + +#include + +uint32_t start, duration; +volatile bool b; + +void setup() +{ + Serial.begin(115200); + Serial.println(__FILE__); + + test_FLOAT_EQ_1(); + test_FLOAT_EQ_2(); + test_DIV2(); + test_POW2(); + + Serial.println("done"); +} + + +void loop() +{ +} + + +void test_FLOAT_EQ_1() +{ + Serial.println(); + Serial.println(__FUNCTION__); + + float f = PI; + float g = PI; + + Serial.print("IEEE_FLOAT_EQ : "); + Serial.println(IEEE_FLOAT_EQ(f, g)); + Serial.print("IEEE_FLOAT_NEQ: "); + Serial.println(IEEE_FLOAT_NEQ(f, g)); + + f += 1; + Serial.print("IEEE_FLOAT_EQ : "); + Serial.println(IEEE_FLOAT_EQ(f, g)); + Serial.print("IEEE_FLOAT_NEQ: "); + Serial.println(IEEE_FLOAT_NEQ(f, g)); + + Serial.println(); +} + + +void test_FLOAT_EQ_2() +{ + Serial.println(); + Serial.println(__FUNCTION__); + delay(10); + + float f = PI; + float g = PI; + start = micros(); + b = (f == g); + duration = micros() - start; + Serial.print("TIME : "); + Serial.println(duration); + delay(10); + + start = micros(); + b = IEEE_FLOAT_EQ(f, g); + duration = micros() - start; + Serial.print("TIME : "); + Serial.println(duration); + delay(10); + + g += 1; + start = micros(); + b = (f == g); + duration = micros() - start; + Serial.print("TIME : "); + Serial.println(duration); + delay(10); + + start = micros(); + b = IEEE_FLOAT_EQ(f, g); + duration = micros() - start; + Serial.print("TIME : "); + Serial.println(duration); + + Serial.println(); +} + + +void test_DIV2() +{ + Serial.println(); + Serial.println(__FUNCTION__); + delay(10); + + volatile float f = random(1000) * 0.01; + Serial.print("VALUE: "); + Serial.println(f, 10); + delay(10); + + start = micros(); + float g = f / 2; + duration = micros() - start; + Serial.print("TIME : "); + Serial.println(duration); + Serial.print("VALUE: "); + Serial.println(f, 10); + Serial.print("VALUE: "); + Serial.println(g, 10); + delay(10); + + start = micros(); + g = IEEE_FLOAT_DIV2(f); + duration = micros() - start; + Serial.print("TIME : "); + Serial.println(duration); + Serial.print("VALUE: "); + Serial.println(f, 10); + Serial.print("VALUE: "); + Serial.println(g, 10); + delay(10); + + start = micros(); + g = IEEE_FLOAT_POW2fast(f, -1); + duration = micros() - start; + Serial.print("TIME : "); + Serial.println(duration); + Serial.print("VALUE: "); + Serial.println(f, 10); + Serial.print("VALUE: "); + Serial.println(g, 10); + delay(10); + + Serial.println(); +} + + +void test_POW2() +{ + Serial.println(); + Serial.println(__FUNCTION__); + delay(10); + + int p = random(10); + float f = random(1000) * 0.001; + Serial.println(f, 10); + delay(10); + + start = micros(); + float g = f * pow(2, p); + duration = micros() - start; + Serial.print("TIME : "); + Serial.println(duration); + Serial.print("VALUE: "); + Serial.println(g, 10); + delay(10); + + start = micros(); + g = IEEE_POW2(f, p); + duration = micros() - start; + Serial.print("TIME : "); + Serial.println(duration); + Serial.print("VALUE: "); + Serial.println(g, 10); + delay(10); + + start = micros(); + g = IEEE_FLOAT_POW2fast(f, p); + duration = micros() - start; + Serial.print("TIME : "); + Serial.println(duration); + Serial.print("VALUE: "); + Serial.println(g, 10); + delay(10); + + Serial.println(); +} + + + + +// -- END OF FILE -- diff --git a/libraries/IEEE754tools/examples/float2double/float2double.ino b/libraries/IEEE754tools/examples/float2double/float2double.ino index 14bd1d32..ca0dec5d 100644 --- a/libraries/IEEE754tools/examples/float2double/float2double.ino +++ b/libraries/IEEE754tools/examples/float2double/float2double.ino @@ -5,6 +5,11 @@ // PURPOSE: experimental expands a float in a IEEE 754 double to be printed to PC. // +// NOTE +// - WORKS ON AVR +// - FAILS ON ESP32 + + #include byte x[8]; @@ -24,6 +29,7 @@ void setup() void test1() { Serial.println(); + Serial.println(__FUNCTION__); for (float f = -50.0; f < 50.0; f += 10.0) { dumpFloat(f); @@ -38,6 +44,8 @@ void test1() void test2() { + Serial.println(); + Serial.println(__FUNCTION__); Serial.println("\n0.15625"); dumpFloat(0.15625); // sign = 0 @@ -47,7 +55,9 @@ void test2() void test3() { - Serial.println("\nPI-check"); + Serial.println(); + Serial.println(__FUNCTION__); + Serial.println("PI-check"); Serial.println(PI, 20); float2DoublePacked(PI, x); dumpByteArray(x); @@ -58,7 +68,9 @@ void test3() void test4() { - Serial.println("\nBIG-check"); + Serial.println(); + Serial.println(__FUNCTION__); + Serial.println("BIG-check"); Serial.println(1.23456789e38, 20); dumpFloat(1.23456789e38); float2DoublePacked(1.23456789e38, x); @@ -74,20 +86,16 @@ void loop() { } - - - - - - - void dumpByteArray(byte *ar) { for (int i = 0; i < 8; i++) { if (ar[i] < 0x10) Serial.print('0'); Serial.print(ar[i], HEX); - Serial.print('\t'); + Serial.print(' '); } Serial.println(); } + + +// -- END OF FILE -- diff --git a/libraries/IEEE754tools/library.json b/libraries/IEEE754tools/library.json index ad561d8b..3f783d76 100644 --- a/libraries/IEEE754tools/library.json +++ b/libraries/IEEE754tools/library.json @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/RobTillaart/IEEE754tools.git" }, - "version": "0.2.1", + "version": "0.2.2", "license": "MIT", "frameworks": "arduino", "platforms": "*" diff --git a/libraries/IEEE754tools/library.properties b/libraries/IEEE754tools/library.properties index 2295b4d8..c1336ba3 100644 --- a/libraries/IEEE754tools/library.properties +++ b/libraries/IEEE754tools/library.properties @@ -1,5 +1,5 @@ name=IEEE754tools -version=0.2.1 +version=0.2.2 author=Rob Tillaart maintainer=Rob Tillaart sentence=Fast helper functions for IEEE754 floats. diff --git a/libraries/IEEE754tools/readme.md b/libraries/IEEE754tools/readme.md index fd4705e2..f3d451b9 100644 --- a/libraries/IEEE754tools/readme.md +++ b/libraries/IEEE754tools/readme.md @@ -1,5 +1,7 @@ [![Arduino CI](https://github.com/RobTillaart/IEEE754tools/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci) +[![Arduino-lint](https://github.com/RobTillaart/IEEE754tools/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/IEEE754tools/actions/workflows/arduino-lint.yml) +[![JSON check](https://github.com/RobTillaart/IEEE754tools/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/IEEE754tools/actions/workflows/jsoncheck.yml) [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/IEEE754tools/blob/master/LICENSE) [![GitHub release](https://img.shields.io/github/release/RobTillaart/IEEE754tools.svg?maxAge=3600)](https://github.com/RobTillaart/IEEE754tools/releases) @@ -8,11 +10,12 @@ Arduino library to manipulate IEEE754 float numbers fast. + ## Description -IEEE754tools.h contains a collection of bit-hacks to speed up a number -of operations on floating point numbers on the Arduino. These bit-hacks -started in 2010 (oldest code found) or maybe even earlier. +IEEE754tools.h contains a collection of experimental bit-hacks to speed up +a number of operations on floating point numbers on the **Arduino UNO**. +These bit-hacks started in 2010 (oldest code found), maybe even earlier. http://en.wikipedia.org/wiki/Double_precision @@ -21,17 +24,37 @@ http://en.wikipedia.org/wiki/Single-precision_floating-point_format ## WARNING -- If you don't need micro-second speedups **do not use** these code snippets. -- code is experimental, so use with care. -- only tested on UNO +- **do not use** this lib for production code unless you verified the correctness. +Code is experimental, so use with care at your own risk. +- If you don't need micro-second speed ups **do not use** these code snippets. +- **do not use for ESP32** ESP32 does things differently ==> not all code works. + + +## Test results examples + +updated for 0.2.2 + +| example | UNO | ESP32 | +|:--------------|:------:|:-------:| +| fastNegate | Y | Y | +| float2Double | Y | N | +| IEEE754_equal | Y | N | + + +ESP32 - needs investigation as UNO verified code fails. +(something for a long winter) + ## Future -- investigate other speedups -- write more examples -- test on ESP32 - test with double -- binary transfer over Serial +- test on ESP23 +- investigate other speed ups +- write more examples +- example binary transfer over Serial +- example binary transfer over Ethernet +- bring more structure in this library. + ## Operations diff --git a/libraries/IEEE754tools/test/unit_test_001.cpp b/libraries/IEEE754tools/test/unit_test_001.cpp index 187e6b85..a4b21180 100644 --- a/libraries/IEEE754tools/test/unit_test_001.cpp +++ b/libraries/IEEE754tools/test/unit_test_001.cpp @@ -60,7 +60,7 @@ unittest(test_new_operator) unittest(test_all) { - fprintf(stderr, "VERSION: %s\n", IEEE754_VERSION); + fprintf(stderr, "VERSION: %s\n", (char*) IEEE754_VERSION); fprintf(stderr, "Convert PI to double and back\n"); uint8_t ar[8];