mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
0.4.0 printHelpers
This commit is contained in:
parent
b4704e95d9
commit
4c65b33e04
@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
|
||||
## [0.4.0] - 2023-01-28
|
||||
- bump version number as fix in 0.3.1 was serious
|
||||
- add **toRoman()**
|
||||
- add toRoman example
|
||||
- redo **toBytes()** (less RAM)
|
||||
- update readme.md
|
||||
- update unit test
|
||||
- minor edits
|
||||
|
||||
----
|
||||
|
||||
## [0.3.1] - 2023-01-27
|
||||
- fix **scieng()** itoa() => sprintf() + conditional ESP32
|
||||
- add leading 0 for exponents smaller than 10, to better align columns.
|
||||
@ -15,7 +26,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- update readme.md
|
||||
- minor edits
|
||||
|
||||
|
||||
## [0.3.0] - 2022-11-29
|
||||
- add hex(value, digits) + bin(value, digits) 32 and 64 bit
|
||||
- leading zero's - no separators - no prefix.
|
||||
|
@ -23,11 +23,12 @@ data in a way not possible in the standard print library of the Arduino.
|
||||
- **toBytes()** generates KB MB GB etc.
|
||||
- **hex()** generates hexadecimal output with leading zeros up to **uint64_t**.
|
||||
- **bin()** generates binary output with leading zeros up to **uint64_t**.
|
||||
- **toRoman()** generates a ROMAN representation of a (positive) number.
|
||||
|
||||
Details, see below.
|
||||
|
||||
|
||||
#### thread safety
|
||||
#### Thread safety
|
||||
|
||||
Note the functions of this library all share an internal buffer, so the library is
|
||||
definitely **not** thread safe.
|
||||
@ -85,7 +86,7 @@ thousands, millions etc which are powers of 3.
|
||||
float or double to a char array.
|
||||
**sci()** and **eng()** use the same underlying function called **scieng()**
|
||||
as the initial code for converting was almost identical.
|
||||
Although not intended to be used directly, one can use it.
|
||||
Although not intended to be used directly, one may use it.
|
||||
The last parameter **exponentMultiple** defines where the exponent is a multiple of.
|
||||
For the **sci()** function this is 1, for the **eng()** function this is 3.
|
||||
The **scieng()** function works for multiples from 1..9 for the exponent.
|
||||
@ -100,18 +101,30 @@ mantissa.
|
||||
representing an amount of bytes a shorter string usable for displaying.
|
||||
The number of decimals is max 3
|
||||
Example 3.292.528 ==> "3.140 MB"
|
||||
|
||||
Value ranges supported are in steps of powers of 1024.
|
||||
These will all be shown in UPPERCASE so KB, MB etc.
|
||||
List of prefixes:
|
||||
- kilo mega giga tera (1024\^4)
|
||||
- peta exa zetta yotta (1024\^8)
|
||||
- xona weka vunda uda (1024\^12)
|
||||
treda Byte == TDB uses 2 chars to indicate the magnitude so that would
|
||||
take extra memory or more complex code.
|
||||
As it is seldom used, "official" support stops with UDA.
|
||||
|
||||
| Unit | abbrev. | size | Unit | abbrev. | size |
|
||||
|:-----------:|:---------:|:--------:|:------------:|:---------:|:--------:|
|
||||
| kilobytes | KB | 1024 | zettabytes | KB | 1024^7 |
|
||||
| megabytes | MB | 1024^2 | yottabytes | MB | 1024^8 |
|
||||
| gigabytes | GB | 1024^3 | xonaytes | GB | 1024^9 |
|
||||
| terabytes | TB | 1024^4 | wekabytes | TB | 1024^10 |
|
||||
| petabytes | PB | 1024^5 | vundabytes | PB | 1024^11 |
|
||||
| exabytes | EB | 1024^6 | udabytes | EB | 1024^12 |
|
||||
|
||||
|
||||
Treda Byte is shortened as "TDB" and uses 2 chars to indicate the magnitude.
|
||||
That would take extra memory or slightly more complex code.
|
||||
As it is very seldom used, "official" support stops with UDA.
|
||||
Should be big enough for some time.
|
||||
To have some support the code uses lowercase for the next 8 levels:
|
||||
|
||||
Note: max uint64_t 2^64 is in the order of exa or zetta bytes.
|
||||
|
||||
To have some support for the really big sizes the code uses lowercase for the next 8 levels:
|
||||
treda sorta rinta quexa pepta ocha nena minga luma (1024\^21 ~~ 10\^63)
|
||||
To enable this patch the function in the **printHelpers.cpp** file.
|
||||
|
||||
|
||||
#### hex() bin()
|
||||
@ -138,12 +151,46 @@ Note: Data types not supported, must be cast to an supported type.
|
||||
Note: There is overlap between **hex(value)** and **print64(value, HEX)**.
|
||||
The latter does not produce the leading zero's or fixed length output.
|
||||
|
||||
----
|
||||
|
||||
More formatting functions might be added in the future.
|
||||
#### toRoman()
|
||||
|
||||
https://en.wikipedia.org/wiki/Roman_numerals
|
||||
|
||||
A less used but well known print format are the Roman digits.
|
||||
The library function **toRoman()** will convert any number from 0..100 million into a Roman number.
|
||||
The numbers 1..5000 ("official" range) are the well known UPPER case characters.
|
||||
|
||||
- **char \* toRoman(uint32_t value)** returns Roman string.
|
||||
|
||||
| char | unit | notes |
|
||||
|:------:|:-------|:------------|
|
||||
| M | 1000 | M = Mille |
|
||||
| D | 500 |
|
||||
| C | 100 | C = Cent |
|
||||
| L | 50 |
|
||||
| X | 10 |
|
||||
| V | 5 |
|
||||
| I | 1 |
|
||||
| N | 0 | extension |
|
||||
|
||||
|
||||
## Shared buffer
|
||||
Note: The maximum length returned is 16 characters in the "official" supported range.
|
||||
4888 == MMMMDCCCLXXXVIII.
|
||||
|
||||
Notes:
|
||||
- value == 0 => N is not part of the "official" numbers but we need it.
|
||||
- values < 0 are not supported (note parameter is unsigned)
|
||||
- values between 5K-10K are extended with extra M chars.
|
||||
- values 10K-100M are represented with lower case characters.
|
||||
This is not a standard, but it sort of works well.
|
||||
- values > 100M return OVF == overflow.
|
||||
- There is no special 'subtract code' for 9000 to have a clear distinction between
|
||||
"official" and extended numbers.
|
||||
- The number 4 is often written as IIII on clocks with Roman digits,
|
||||
although IV would be (more?) correct and therefore IV is used.
|
||||
|
||||
|
||||
## Shared print buffer
|
||||
|
||||
The implementation of the function all use a shared buffer to hold the
|
||||
generated string.
|
||||
@ -172,32 +219,26 @@ In practice a size of 22 will work for most applications.
|
||||
When functions are added, the recommended minimum size might increase.
|
||||
|
||||
|
||||
## Operation
|
||||
|
||||
See examples.
|
||||
|
||||
|
||||
## Future
|
||||
|
||||
#### Must
|
||||
|
||||
- check TODO's in the code
|
||||
|
||||
|
||||
#### Should
|
||||
|
||||
- documentation
|
||||
- table for toBytes() - values KB, MB etc. (21 entries 3 x 7 ?) range etc.
|
||||
- improve readability of the code
|
||||
|
||||
|
||||
#### Could
|
||||
|
||||
- investigate separators in **hex()**
|
||||
- space per 8, 4 or 2
|
||||
- investigate thread safe version
|
||||
- pass char buffer as parameter (breaking)
|
||||
- could be the log10 pow version?
|
||||
- investigate **toRoman()**
|
||||
- investigate separators in **hex()**
|
||||
- space per 8, 4 or 2
|
||||
- investigate distance print helpers.
|
||||
- feet(float cm) as 3'2" or 3-7/8 feet
|
||||
- inch(float cm) as 32"
|
||||
|
@ -0,0 +1,53 @@
|
||||
|
||||
Arduino UNO
|
||||
IDE 1.8.19
|
||||
|
||||
print_performance.ino
|
||||
PRINTHELPERS_VERSION: 0.4.0
|
||||
|
||||
4
|
||||
4
|
||||
|
||||
Mass moon M = 7.34767309E+20
|
||||
Speed of light c = 2.99792458E+8
|
||||
Print E = Mc^2 = 6.6037592413026551656653076E+37
|
||||
|
||||
|
||||
|
||||
print64
|
||||
TIME: 22476
|
||||
660375892052148224
|
||||
|
||||
SCI
|
||||
TIME: 9236
|
||||
6.603759288787841E+17
|
||||
|
||||
ENG
|
||||
TIME: 7392
|
||||
660.375976562500000E+15
|
||||
|
||||
dtostrf
|
||||
TIME: 2464
|
||||
660375890000000000.000000000000000
|
||||
|
||||
dtostre
|
||||
TIME: 1456
|
||||
6.6037589e+17
|
||||
|
||||
toBytes
|
||||
TIME: 1980
|
||||
586.531 PB
|
||||
|
||||
hex
|
||||
TIME: 1276
|
||||
092A206000000000
|
||||
|
||||
bin
|
||||
TIME: 2464
|
||||
0000100100101010001000000110000000000000000000000000000000000000
|
||||
|
||||
toRoman
|
||||
TIME: 90164
|
||||
CMXCIX
|
||||
|
||||
done...
|
@ -27,7 +27,7 @@ void setup()
|
||||
Serial.println();
|
||||
Serial.println(" Mass moon M = 7.34767309E+20");
|
||||
Serial.println("Speed of light c = 2.99792458E+8");
|
||||
Serial.println(" Print E = Mc^2 = 6.6037592413026551656653076E+37\n");
|
||||
Serial.println(" Print E = Mc^2 = 6.6037592413026551656653076E+37 \n");
|
||||
Serial.println();
|
||||
|
||||
E = 660375924130265516;
|
||||
@ -148,10 +148,19 @@ void setup()
|
||||
delay(100);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Serial.println();
|
||||
Serial.println("toRoman");
|
||||
delay(100);
|
||||
start = micros();
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
b = toRoman(i);
|
||||
}
|
||||
stop = micros();
|
||||
Serial.print("TIME: ");
|
||||
Serial.println(stop - start);
|
||||
Serial.println(b);
|
||||
delay(100);
|
||||
|
||||
Serial.println();
|
||||
Serial.println("done...");
|
||||
|
@ -22,7 +22,7 @@ void setup()
|
||||
Serial.println();
|
||||
Serial.println(" Mass moon M = 7.34767309E+20");
|
||||
Serial.println("Speed of light c = 2.99792458E+8");
|
||||
Serial.println(" Print E = Mc^2 = 6.6037592413026551656653076E+37\n");
|
||||
Serial.println(" Print E = Mc^2 = 6.6037592413026551656653076E+37 \n");
|
||||
|
||||
Serial.print(" normal print:\t");
|
||||
Serial.println(E, 4);
|
||||
|
@ -0,0 +1,56 @@
|
||||
// FILE: print_toRoman.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo program toRoman
|
||||
|
||||
|
||||
#include "printHelpers.h"
|
||||
|
||||
uint32_t start, stop;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
|
||||
Serial.println(sizeof(float));
|
||||
Serial.println(sizeof(double));
|
||||
|
||||
uint8_t maxlen = 0;
|
||||
|
||||
for (uint32_t i = 1; i <= 5000; i++)
|
||||
{
|
||||
uint8_t len = strlen(toRoman(i));
|
||||
if (maxlen < len)
|
||||
{
|
||||
maxlen = len;
|
||||
Serial.print(i);
|
||||
Serial.print("\t");
|
||||
Serial.println(toRoman(i));
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
Serial.print("MAXLEN: ");
|
||||
Serial.println(maxlen);
|
||||
Serial.println();
|
||||
delay(1000);
|
||||
|
||||
start = micros();
|
||||
char * b;
|
||||
for (int i = 1; i <= 5000; i++)
|
||||
{
|
||||
b = toRoman(i);
|
||||
}
|
||||
stop = micros();
|
||||
Serial.println((stop - start) / 5000.0);
|
||||
Serial.println(b);
|
||||
delay(1000);
|
||||
|
||||
Serial.println("\ndone...");
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
@ -15,6 +15,8 @@ toBytes KEYWORD2
|
||||
hex KEYWORD2
|
||||
bin KEYWORD2
|
||||
|
||||
toRoman KEYWORD2
|
||||
|
||||
|
||||
# Constants (LITERAL1)
|
||||
PRINTHELPERS_VERSION LITERAL1
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "printHelpers",
|
||||
"keywords": "Convert, int64, uint64, print, scientific, notation, toBytes",
|
||||
"keywords": "Convert,int64,uint64,print,scientific,notation,toBytes,HEX,BIN,Roman",
|
||||
"description": "Arduino library to help printing. int64 and uint64 support base 10 (DEC) and 16 (HEX). Scientific notation of floats.",
|
||||
"authors":
|
||||
[
|
||||
@ -15,7 +15,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobTillaart/printHelpers"
|
||||
},
|
||||
"version": "0.3.1",
|
||||
"version": "0.4.0",
|
||||
"license": "MIT",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "*",
|
||||
|
@ -1,9 +1,9 @@
|
||||
name=printHelpers
|
||||
version=0.3.1
|
||||
version=0.4.0
|
||||
author=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
sentence=Arduino library to help formatting data for printing. 64 bit integers (base 10 and 16). Engineering and scientific notation.
|
||||
paragraph=Supports 64 bit integers (base 10 and 16). Engineering and scientific notation. toBytes() for KB MB etc.
|
||||
paragraph=Supports 64 bit integers (base 10 and 16). Engineering and scientific notation. toBytes() for KB MB, HEX and BIN, Roman numbers.
|
||||
category=Other
|
||||
url=https://github.com/RobTillaart/printHelpers
|
||||
architectures=*
|
||||
|
@ -2,7 +2,7 @@
|
||||
// FILE: printHelpers.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// DATE: 2018-01-21
|
||||
// VERSION: 0.3.1
|
||||
// VERSION: 0.4.0
|
||||
// PUPROSE: Arduino library to help formatting for printing.
|
||||
// URL: https://github.com/RobTillaart/printHelpers
|
||||
|
||||
@ -187,7 +187,8 @@ char * scieng(double value, uint8_t decimals, uint8_t em)
|
||||
|
||||
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||
double rounding = 0.5;
|
||||
// TODO: can we remove loop to reduce rounding errors
|
||||
// TODO: can we remove loop to reduce rounding errors?
|
||||
// additional loop that steps per 1000?
|
||||
for (uint8_t i = 0; i < decimals; ++i)
|
||||
{
|
||||
rounding *= 0.1;
|
||||
@ -222,7 +223,6 @@ char * scieng(double value, uint8_t decimals, uint8_t em)
|
||||
|
||||
// Extract decimals from the remainder one at a time
|
||||
// to prevent missing leading zero's
|
||||
// TODO: can we remove loop to reduce rounding errors
|
||||
while (decimals-- > 0)
|
||||
{
|
||||
remainder *= 10;
|
||||
@ -280,9 +280,13 @@ void sci(Stream &str, double value, uint8_t decimals)
|
||||
// treda sorta rinta quexa pepta ocha nena minga luma (1024 ^21 ~~ 10^63)
|
||||
char * toBytes(double value, uint8_t decimals)
|
||||
{
|
||||
static char buffer[12];
|
||||
char t[] = " KMGTPEZYXWVUtsrqponml";
|
||||
uint8_t i = 0; // i is index of the array == powers of 1024.
|
||||
char * buffer = __printbuffer;
|
||||
// to enable full range uncomment the following line
|
||||
// char units[] = " KMGTPEZYXWVUtsrqponml";
|
||||
|
||||
char units[] = " KMGTPEZYXWVU";
|
||||
uint8_t i = 0; // i is index of the unit array == powers of 1024.
|
||||
|
||||
if (isinf(value))
|
||||
{
|
||||
strcpy(buffer, "<inf>");
|
||||
@ -316,16 +320,16 @@ char * toBytes(double value, uint8_t decimals)
|
||||
}
|
||||
|
||||
// UNITS
|
||||
if (i <= strlen(t))
|
||||
if (i <= strlen(units))
|
||||
{
|
||||
if (i > 0) buffer[pos++] = ' ';
|
||||
buffer[pos++] = t[i];
|
||||
buffer[pos++] = units[i];
|
||||
buffer[pos++] = 'B';
|
||||
buffer[pos] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO e.g. E99 B
|
||||
// no units available
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
@ -351,6 +355,7 @@ char * hex(uint64_t value, uint8_t digits)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// faster than 64 bit.
|
||||
char * hex(uint32_t value, uint8_t digits)
|
||||
{
|
||||
uint32_t val = value;
|
||||
@ -375,7 +380,6 @@ char * hex(uint8_t value, uint8_t digits) { return hex((uint32_t) value, digits
|
||||
// BIN
|
||||
//
|
||||
// always leading zero's - no prefix - no separator
|
||||
|
||||
char * bin(uint64_t value, uint8_t digits)
|
||||
{
|
||||
uint64_t val = value;
|
||||
@ -390,6 +394,7 @@ char * bin(uint64_t value, uint8_t digits)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// faster than 64 bit.
|
||||
char * bin(uint32_t value, uint8_t digits)
|
||||
{
|
||||
uint64_t val = value;
|
||||
@ -408,6 +413,69 @@ char * bin(uint16_t value, uint8_t digits) { return bin((uint32_t) value, digits
|
||||
char * bin(uint8_t value, uint8_t digits) { return bin((uint32_t) value, digits); };
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// toRoman
|
||||
//
|
||||
// experimental
|
||||
// extended with 10K units generated with the same but lower case chars.
|
||||
// would expect a special char for 5000?
|
||||
// need investigation.
|
||||
char * toRoman(uint32_t value)
|
||||
{
|
||||
char * buffer = __printbuffer;
|
||||
uint32_t val = value;
|
||||
uint16_t n[13] = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };
|
||||
char roman[13][3] = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" };
|
||||
|
||||
buffer[0] = 0;
|
||||
int idx = 0;
|
||||
if (value == 0)
|
||||
{
|
||||
strcat(buffer, "N"); // NULL
|
||||
return buffer;
|
||||
}
|
||||
|
||||
if (value > 100000000UL)
|
||||
{
|
||||
strcat(buffer, "OVF"); // overflow
|
||||
return buffer;
|
||||
}
|
||||
|
||||
if (val >= 10000UL)
|
||||
{
|
||||
// 10K units
|
||||
while(val >= 10000UL)
|
||||
{
|
||||
while (val >= (10000UL * n[idx]))
|
||||
{
|
||||
strcat(buffer, roman[idx]);
|
||||
val -= (10000UL * n[idx]);
|
||||
};
|
||||
idx++;
|
||||
}
|
||||
// set chars to lower
|
||||
for (int i = 0; i < strlen(buffer); i++)
|
||||
{
|
||||
buffer[i] = tolower(buffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Official part UPPER case letters
|
||||
while(val > 0)
|
||||
{
|
||||
while (val >= n[idx])
|
||||
{
|
||||
strcat(buffer, roman[idx]);
|
||||
val -= n[idx];
|
||||
};
|
||||
idx++;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
// FILE: printHelpers.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// DATE: 2018-01-21
|
||||
// VERSION: 0.3.1
|
||||
// VERSION: 0.4.0
|
||||
// PUPROSE: Arduino library to help formatting for printing.
|
||||
// URL: https://github.com/RobTillaart/printHelpers
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
#include "stdlib.h"
|
||||
|
||||
|
||||
#define PRINTHELPERS_VERSION (F("0.3.1"))
|
||||
#define PRINTHELPERS_VERSION (F("0.4.0"))
|
||||
|
||||
|
||||
// global buffer used by all functions so no static buffer in every function
|
||||
@ -98,5 +98,14 @@ char * bin(uint16_t value, uint8_t digits = 16);
|
||||
char * bin(uint8_t value, uint8_t digits = 8);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// toRoman()
|
||||
//
|
||||
// value should be in range 1..9999
|
||||
// values 10K-100M are experimental (see readme.md)
|
||||
char * toRoman(uint32_t value);
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
|
@ -138,6 +138,34 @@ unittest(test_bin)
|
||||
}
|
||||
|
||||
|
||||
unittest(test_toRoman_standard)
|
||||
{
|
||||
assertEqual(0, strcmp("I", toRoman(1)) );
|
||||
assertEqual(0, strcmp("II", toRoman(2)) );
|
||||
assertEqual(0, strcmp("III", toRoman(3)) );
|
||||
assertEqual(0, strcmp("VIII", toRoman(8)) );
|
||||
assertEqual(0, strcmp("XVIII", toRoman(18)) );
|
||||
assertEqual(0, strcmp("XXVIII", toRoman(28)) );
|
||||
assertEqual(0, strcmp("XXXVIII", toRoman(38)) );
|
||||
assertEqual(0, strcmp("LXXXVIII", toRoman(88)) );
|
||||
assertEqual(0, strcmp("CLXXXVIII", toRoman(188)) );
|
||||
assertEqual(0, strcmp("CCLXXXVIII", toRoman(288)) );
|
||||
assertEqual(0, strcmp("CCCLXXXVIII", toRoman(388)) );
|
||||
assertEqual(0, strcmp("DCCCLXXXVIII", toRoman(888)) );
|
||||
assertEqual(0, strcmp("MDCCCLXXXVIII", toRoman(1888)) );
|
||||
assertEqual(0, strcmp("MMDCCCLXXXVIII", toRoman(2888)) );
|
||||
assertEqual(0, strcmp("MMMDCCCLXXXVIII", toRoman(3888)) );
|
||||
assertEqual(0, strcmp("MMMMDCCCLXXXVIII", toRoman(4888)) );
|
||||
}
|
||||
|
||||
|
||||
unittest(test_toRoman_extended)
|
||||
{
|
||||
assertEqual(0, strcmp("N", toRoman(0)) );
|
||||
assertEqual(0, strcmp("OVF", toRoman(100000001UL)) );
|
||||
}
|
||||
|
||||
|
||||
unittest_main()
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user