├── .arduino-ci.yml ├── .github ├── FUNDING.yml └── workflows │ ├── arduino-lint.yml │ ├── arduino_test_runner.yml │ └── jsoncheck.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── examples ├── print64 │ └── print64.ino ├── print_comma_separated_integers │ └── print_comma_separated_integers.ino ├── print_fractions │ └── print_fractions.ino ├── print_fractions_denum │ └── print_fractions_denum.ino ├── print_hex_bin │ └── print_hex_bin.ino ├── print_inch_feet │ └── print_inch_feet.ino ├── print_performance │ ├── performance_0.3.0.txt │ ├── performance_0.3.1.txt │ ├── performance_0.4.0.txt │ ├── performance_0.4.1.txt │ ├── performance_0.4.3.txt │ └── print_performance.ino ├── print_sci │ └── print_sci.ino ├── print_sci_experimental │ └── print_sci_experimental.ino ├── print_toRoman │ └── print_toRoman.ino ├── sci_test │ └── sci_test.ino └── toBytes │ └── toBytes.ino ├── keywords.txt ├── library.json ├── library.properties ├── printHelpers.cpp ├── printHelpers.h └── test └── unit_test_001.cpp /.arduino-ci.yml: -------------------------------------------------------------------------------- 1 | platforms: 2 | rpipico: 3 | board: rp2040:rp2040:rpipico 4 | package: rp2040:rp2040 5 | gcc: 6 | features: 7 | defines: 8 | - ARDUINO_ARCH_RP2040 9 | warnings: 10 | flags: 11 | 12 | packages: 13 | rp2040:rp2040: 14 | url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json 15 | 16 | compile: 17 | # Choosing to run compilation tests on 2 different Arduino platforms 18 | # selected only those that work 19 | platforms: 20 | - uno 21 | - due 22 | - zero 23 | - leonardo 24 | - m4 25 | - esp32 26 | - esp8266 27 | - mega2560 28 | - rpipico 29 | 30 | 31 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: RobTillaart 4 | custom: "https://www.paypal.me/robtillaart" 5 | -------------------------------------------------------------------------------- /.github/workflows/arduino-lint.yml: -------------------------------------------------------------------------------- 1 | name: Arduino-lint 2 | 3 | on: [push, pull_request] 4 | jobs: 5 | lint: 6 | runs-on: ubuntu-latest 7 | timeout-minutes: 5 8 | steps: 9 | - uses: actions/checkout@v4 10 | - uses: arduino/arduino-lint-action@v1 11 | with: 12 | library-manager: update 13 | compliance: strict -------------------------------------------------------------------------------- /.github/workflows/arduino_test_runner.yml: -------------------------------------------------------------------------------- 1 | name: Arduino CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | runTest: 7 | runs-on: ubuntu-latest 8 | timeout-minutes: 20 9 | 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: ruby/setup-ruby@v1 13 | with: 14 | ruby-version: 2.6 15 | - run: | 16 | gem install arduino_ci 17 | arduino_ci.rb 18 | -------------------------------------------------------------------------------- /.github/workflows/jsoncheck.yml: -------------------------------------------------------------------------------- 1 | name: JSON check 2 | 3 | on: 4 | push: 5 | paths: 6 | - '**.json' 7 | pull_request: 8 | 9 | jobs: 10 | test: 11 | runs-on: ubuntu-latest 12 | timeout-minutes: 5 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: json-syntax-check 16 | uses: limitusus/json-syntax-check@v2 17 | with: 18 | pattern: "\\.json$" -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log printHelpers 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 6 | and this project adheres to [Semantic Versioning](http://semver.org/). 7 | 8 | 9 | ## [0.4.6] - 2024-11-21 10 | - fix #22, negative fractions 11 | - fix unofficial **toRoman()** for > 4888 12 | - add support for negative sign for **toRoman()** 13 | - changed parameter to signed **toRoman(int32_t value)** 14 | - add unit tests 15 | - update readme.md 16 | 17 | ## [0.4.5] - 2024-11-20 18 | - add experimental **fraction()** 19 | - add **print_fractions.ino** example 20 | - add **print_fractions_denum.ino** example 21 | - update **print_sci_experimental.ino** example 22 | - added define PRINTHELPERS_LIB_VERSION. 23 | - update readme.md 24 | 25 | ## [0.4.4] - 2024-01-05 26 | - fix URL in examples 27 | - minor edits 28 | 29 | ## [0.4.3] - 2023-11-15 30 | - added **csi()** comma separated integers for readability e.g. 123,458,654 31 | - update readme.md. 32 | - update examples 33 | 34 | ## [0.4.2] - 2023-11-15 35 | - update readme.md 36 | - update keywords.txt 37 | 38 | ## [0.4.1] - 2023-07-13 39 | - fix #16 signed/unsigned warning 40 | - update example **print_toRoman.ino** to print 1..5000 41 | - update example **print_sci.ino** when double = 8 bytes. 42 | - update readme.md 43 | - fix description range **toBytes()** 44 | - change return type of **size_t sci(Stream, value, decimals)** 45 | - add **printInch(inch, step)** e.g 7 7/16 46 | - add **printFeet(feet)** 47 | 48 | ## [0.4.0] - 2023-01-28 49 | - bump version number as fix in 0.3.1 was serious 50 | - add **toRoman()** 51 | - add toRoman example 52 | - redo **toBytes()** (less RAM) 53 | - update readme.md 54 | - update unit test 55 | - minor edits 56 | 57 | ---- 58 | 59 | ## [0.3.1] - 2023-01-27 60 | - fix **scieng()** itoa() => sprintf() + conditional ESP32 61 | - add leading 0 for exponents smaller than 10, to better align columns. 62 | - update GitHub actions 63 | - update license 2023 64 | - add performance example 65 | - update readme.md 66 | - minor edits 67 | 68 | ## [0.3.0] - 2022-11-29 69 | - add hex(value, digits) + bin(value, digits) 32 and 64 bit 70 | - leading zero's - no separators - no prefix. 71 | - add example show the difference 72 | - update readme.md 73 | - update unit test 74 | 75 | ---- 76 | 77 | ## [0.2.5] - 2022-11-22 78 | - add changelog.md 79 | - add RP2040 to build-CI 80 | 81 | ## [0.2.4] - 2022-04-15 82 | - no info 83 | 84 | ## [0.2.3] - 2021-24-12 85 | 86 | ## [0.2.2] - 2021-11-13 87 | 88 | ---- 89 | 90 | ## [0.1.0] - 2018-01-21 91 | - initial version 92 | 93 | 94 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2024 Rob Tillaart 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![Arduino CI](https://github.com/RobTillaart/printHelpers/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci) 3 | [![Arduino-lint](https://github.com/RobTillaart/printHelpers/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/printHelpers/actions/workflows/arduino-lint.yml) 4 | [![JSON check](https://github.com/RobTillaart/printHelpers/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/printHelpers/actions/workflows/jsoncheck.yml) 5 | [![GitHub issues](https://img.shields.io/github/issues/RobTillaart/printHelpers.svg)](https://github.com/RobTillaart/printHelpers/issues) 6 | 7 | [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/printHelpers/blob/master/LICENSE) 8 | [![GitHub release](https://img.shields.io/github/release/RobTillaart/printHelpers.svg?maxAge=3600)](https://github.com/RobTillaart/printHelpers/releases) 9 | [![PlatformIO Registry](https://badges.registry.platformio.org/packages/robtillaart/library/printHelpers.svg)](https://registry.platformio.org/libraries/robtillaart/printHelpers) 10 | 11 | 12 | # printHelpers 13 | 14 | Arduino library to help formatting data for printing. 15 | 16 | 17 | ## Description 18 | 19 | The printHelpers library contains a number of functions that help to print 20 | data in a way not supported in the standard print library of the Arduino. 21 | 22 | - **char \* print64()** returns a string for **uint64_t** and **int64_t**. 23 | - **char \* sci()** returns a string in scientific format - exponent has step 1. 24 | - **char \* eng()** returns a string in engineering format - exponent has step 3. 25 | - **char \* scieng()** returns a string in exponential format - exponent has step 1 to 9. 26 | - **char \* toBytes()** returns a string in KB MB GB etc. 27 | - **char \* hex()** returns hexadecimal output with **leading zeros** up to **uint64_t**. 28 | - **char \* bin()** returns binary output with **leading zeros** up to **uint64_t**. 29 | - **char \* toRoman()** returns a ROMAN representation of a number. 30 | - **char \* printInch(float inch, uint16_t step)** returns a string e.g. 5 7/8". 31 | - **char \* printFeet(float feet)** returns a string e.g. 7"4' 32 | - **char \* csi()** returns a comma separated integer for readability e.g. 3,254,152. 33 | - **char \* fraction()** returns a fraction representation of a double/float e.g. 355/113. 34 | 35 | For the details, see sections below. 36 | 37 | If a (generic) print format is missing, please open an issue. 38 | 39 | 40 | ### Thread safety 41 | 42 | Note the functions of this library all share an internal buffer, so the library is 43 | definitely **not** thread safe. 44 | Therefore one should copy / print the data (returned pointer) as fast as possible. 45 | 46 | Thread-safe versions of these print functions might be made in the future. 47 | 48 | 49 | ### Related 50 | 51 | - https://github.com/RobTillaart/Fraction 52 | - https://github.com/RobTillaart/lineFormatter (for tabular formatting) 53 | 54 | 55 | ## Interface 56 | 57 | ```cpp 58 | #include "printHelpers.h" 59 | ``` 60 | 61 | The following functions are implemented: 62 | 63 | 64 | ### print64() 65 | 66 | - **char \* print64(int64_t value, uint8_t base = 10)** converts a 64 bit integer 67 | number to a char array. 68 | The plus sign is not printed, neither are leading zero's. 69 | Base 10 (DEC) and 16 (HEX) are supported and other bases up to 36 can be used. 70 | Default base == 10 == decimal. 71 | Note that negative numbers will always get a minus sign for any base. 72 | Cast the number to uint64_t to suppress the sign. 73 | 74 | - **char \* print64(uint64_t value, uint8_t base = 10)** converts a unsigned 64 bit 75 | int number to a char array. 76 | No sign is printed, neither are leading zero's. 77 | Base 10 (DEC) and 16 (HEX) are supported and bases up to 36 can be used. 78 | Default base == 10 == decimal. 79 | 80 | 81 | ### sci() eng() 82 | 83 | - **char \* sci(double value, uint8_t decimals)** converts a float or double to a 84 | char array. 85 | E.g. **print(sci(f, 4))** ==> results in **"6.7407E+21"**. 86 | The existing Arduino print library only supports printing of floats and 87 | doubles up to about 4E9 while the range of floats goes up to ~1E38. 88 | The smallest float values will often be printed as 0.00 while floats 89 | support down to about 1E-38 (subnormal even to 1E-45). 90 | The existing (AVR) library function **dtostrf()** has no scientific notation 91 | and **dtostre()** is limited to 7 decimals. These latter two are faster. 92 | Values printed with **sci()** do look often pretty in column output. 93 | 94 | - **size_t sci(Stream &str, double value, uint8_t decimals)** as above. 95 | Prints directly to a stream, returning bytes printed. 96 | 97 | - **char \* eng(double value, uint8_t decimals)** converts a float or double to a 98 | char array. 99 | E.g. print(eng(f, 4)) ==> results in "6.7407E+21". 100 | Note the exponent created by **eng()** is always a multiple of 3. 101 | Values printed with **eng()** do not always look pretty in column output. 102 | This is due to the exponent power of 3. However its output translates easy to 103 | thousands, millions, billions, and millis, micros, nano etc. which are powers of 3. 104 | 105 | - **char \* scieng(double value, uint8_t decimals, uint8_t exponentMultiple)** converts a 106 | float or double to a char array. 107 | **sci()** and **eng()** use the same underlying function called **scieng()** 108 | as the initial code for converting was almost identical. 109 | Although not intended to be used directly, feel free to use it. 110 | The last parameter **exponentMultiple** defines where the exponent is a multiple of. 111 | For the **sci()** function this is 1, for the **eng()** function this is 3. 112 | The **scieng()** function works for multiples from 1..9 for the exponent. 113 | The usability of other values than 1 and 3 are not known. 114 | Personally I like the multiple of 2 as I get 2 orders of magnitude in the 115 | mantissa. This is e.g. useful for temperature Celsius or percentages. 116 | 117 | 118 | ### toBytes() 119 | 120 | - **char \* toBytes(double value, uint8_t decimals = 2)** converts a big number 121 | representing an amount of bytes to a shorter string usable for displaying. 122 | The string uses official extensions. 123 | 124 | The number of decimals is max 3, example: 3.292.528 ==> "3.140 MB" 125 | 126 | Value ranges supported are in steps of powers of 1024. 127 | These will all be shown in UPPERCASE so KB, MB etc. 128 | 129 | | Unit | abbrev. | size | Unit | abbrev. | size | 130 | |:-----------:|:---------:|:--------:|:------------:|:---------:|:--------:| 131 | | bytes | B | 1024^0 | | | | 132 | | kilobytes | KB | 1024^1 | zettabytes | ZB | 1024^7 | 133 | | megabytes | MB | 1024^2 | yottabytes | YB | 1024^8 | 134 | | gigabytes | GB | 1024^3 | xonaytes | XB | 1024^9 | 135 | | terabytes | TB | 1024^4 | wekabytes | WB | 1024^10 | 136 | | petabytes | PB | 1024^5 | vundabytes | VB | 1024^11 | 137 | | exabytes | EB | 1024^6 | udabytes | UB | 1024^12 | 138 | 139 | 140 | #### Bigger 141 | 142 | Treda Byte is officially shortened as "TDB" and uses 2 chars to indicate the magnitude. 143 | That would take extra memory or slightly more complex code. 144 | As it is very seldom used, "official" support stops with UDA. 145 | Should be big enough for some time. 146 | 147 | Note: max uint64_t == 2^64 is in the order of exa or zetta bytes. 148 | 149 | To have some support for the really big sizes the code uses lowercase for the next 8 levels: 150 | To enable this patch the function in the **printHelpers.cpp** file. 151 | 152 | | Unit | abbrev. | size | 153 | |:-----------:|:---------:|:---------:| 154 | | tredabytes | tB | 1024^13 | 155 | | sortabytes | sB | 1024^14 | 156 | | rintabytes | rB | 1024^15 | 157 | | quexabytes | qB | 1024^16 | 158 | | peptabytes | pB | 1024^17 | 159 | | ochabytes | oB | 1024^18 | 160 | | nenabytes | nB | 1024^19 | 161 | | mingabytes | mB | 1024^20 | 162 | | lumabytes | lB | 1024^21 | 163 | 164 | Note that from the ZETTA prefix all higher prefixes are starting with the 165 | previous letter of the alphabet ZYXWVUtsrqponml 166 | 167 | 168 | ### hex() bin() 169 | 170 | The default print() function of Arduino does not have leading zero's 171 | for **HEX** and **BIN**. 172 | This often causes a "broken" layout especially if one wants to print 173 | the output in columns or so. 174 | 175 | To solve this the following functions are added that will generate a 176 | constant length char array. 177 | 178 | - **char \* hex(uint64_t value, uint8_t digits = 16)** 179 | - **char \* hex(uint32_t value, uint8_t digits = 8)** 180 | - **char \* hex(uint16_t value, uint8_t digits = 4)** 181 | - **char \* hex(uint8_t value, uint8_t digits = 2)** 182 | - **char \* bin(uint64_t value, uint8_t digits = 64)** 183 | - **char \* bin(uint32_t value, uint8_t digits = 32)** 184 | - **char \* bin(uint16_t value, uint8_t digits = 16)** 185 | - **char \* bin(uint8_t value, uint8_t digits = 8)** 186 | 187 | Note: Data types not supported, must be cast to an supported type. 188 | 189 | Note: There is overlap between **hex(value)** and **print64(value, HEX)**. 190 | The latter does not produce the leading zero's or fixed length output. 191 | 192 | Note: hex() does not print hex indicator like "0x" or "H" in front. 193 | 194 | Note: bin() does not print bin indicator like "b" at the end. 195 | 196 | 197 | ### toRoman() 198 | 199 | https://en.wikipedia.org/wiki/Roman_numerals 200 | 201 | A less used but well known print format are the Roman digits. 202 | The library function **toRoman()** will convert any number from 0..100 million into a Roman number. 203 | The numbers 1..5000 ("official" range) are the well known UPPER case characters. 204 | 205 | - **char \* toRoman(int32_t value)** returns Roman string. 206 | 207 | | char | unit | notes | 208 | |:------:|:-------|:------------| 209 | | M | 1000 | M = Mille | 210 | | D | 500 | 211 | | C | 100 | C = Cent | 212 | | L | 50 | 213 | | X | 10 | 214 | | V | 5 | 215 | | I | 1 | 216 | | N | 0 | extension | 217 | 218 | 219 | Note: The maximum length returned is 16 characters in the "official" supported range. 220 | 4888 == MMMMDCCCLXXXVIII. 221 | 222 | Notes: 223 | - value == 0 => N is not part of the "official" numbers but we need it. 224 | - values between 5K-10K are extended with extra M chars. 225 | - values 10K-100M are represented with lower case characters. 226 | This is not a standard, but it sort of works well. 227 | - values > 100M return OVF == overflow. 228 | - There is no special 'subtract code' for 9000 to have a clear distinction between 229 | "official" and extended numbers. 230 | - The number 4 is often written as IIII on clocks with Roman digits, 231 | although IV would be (more?) correct and therefore IV is used. 232 | The reason for IIII is that it is opposite of VIII giving a visual balance. 233 | 234 | Since 0.4.6 negative numbers will have a - sign in front. 235 | 236 | 237 | ### Distance feet inch 238 | 239 | Experimental 0.4.1 240 | 241 | - **char \* printInch(float inch, uint16_t step = 16)** prints a float inch distance default in sixteenth ```a b/16```. 242 | The parameter step must be a power of 2 == 2, 4, 8, 16, 32, 64, 128. 243 | 244 | - **char \* printFeet(float feet)** prints a float feet distance as 245 | ``` a'b"``` e.g. 4.5 feet prints as ```4'6"``` 246 | 247 | 248 | ### Comma Separated Integer 249 | 250 | Experimental 0.4.3 251 | 252 | When you are working with large numbers, more than lets say 6 digits. 253 | With these numbers it is often difficult to see if it is 2 million something or 20 million something. 254 | A proven way to solve this is to print those large numbers in groups of 3 digits separated by comma's. 255 | This improves the readability a lot and yes the price is more room needed on a display. 256 | The comma is chosen as it is default thousands separator in Excel. 257 | 258 | In the first version the separator is hardcoded a ",", in future it might be configurable. 259 | This new printHelper function can work with both signed and unsigned up to 64 bit numbers. 260 | Like all printHelper functions it uses a shared print buffer to keep memory usage low. 261 | 262 | Example 192837465 becomes 192,837,465. 263 | 264 | signed 265 | - **char \* csi(int64_t n)** 266 | - **char \* csi(int32_t n)** 267 | - **char \* csi(int16_t n)** 268 | - **char \* csi(int8_t n)** 269 | 270 | unsigned 271 | - **char \* csi(uint64_t n)** 272 | - **char \* csi(uint32_t n)** 273 | - **char \* csi(uint16_t n)** 274 | - **char \* csi(uint8_t n)** 275 | 276 | 277 | ### Fraction 278 | 279 | Experimental 0.4.5, based upon Fraction class. 280 | 281 | The precision is hard set to absolute 1e-6. 282 | The fraction will have a numerator and denumerator in the range 1..99999. 283 | Note that as floats only have 7 significant digits the precision varies 284 | especially for numbers above 1 (as decimal part eats up significant digits). 285 | 286 | The algorithm is primary meant for values between 0 and 1 however any float 287 | will be processed. The algorithm does not always come up with the best 288 | fraction 289 | 290 | Time is not constant, e.g. **fraction(PI)** takes about 620 us on an Arduino UNO 16 MHz. 291 | 292 | - **char \* fraction(double value)** approach the value with a fraction like n / d. 293 | - **char \* fraction(double value, uint16_t denom)** choose the denominator. 294 | Note it will be reduced if possible e.g. 6/8 => 3/4 295 | 296 | If you have a faster or more accurate algorithm or both please let me know 297 | and open an issue. 298 | 299 | 300 | ## Shared print buffer 301 | 302 | The implementation of the function all use a shared buffer to hold the 303 | generated string. 304 | This is done to reduce the memory overhead of embedding static buffers. 305 | **Note this is not thread safe!** 306 | In a coming release the functions will be able to pass a buffer to them 307 | to become more thread safe. 308 | 309 | The size of this shared buffer is default 66 to be able to print a 64 bit 310 | integer in base 2. 311 | To save memory one can change this buffer size in the code or compile time 312 | by changing **PRINTBUFFERSIZE** in printHelpers.h. 313 | Be aware that **sci()** and **eng()** use the same buffer. 314 | These functions need about 10 bytes plus one bytes for every decimal used. 315 | So for floats one need 15-20 bytes max, for doubles one need up to 30 bytes max. 316 | In practice a size of 22 will work for most applications. 317 | 318 | | PRINTBUFFERSIZE | BASE SUPPORTED | nr. decimals | Notes | 319 | |:---------------:|:--------------:|:------------:|:----------| 320 | | 66 | 02 - 36 | 0 - 50 | (default) | 321 | | 34 | 04 - 36 | 0 - 20 | 322 | | 24 | 08 - 36 | 0 - 14 | 323 | | 22 | 10 - 36 | 0 - 12 | 324 | | 18 | 16 - 36 | 0 - 07 | 325 | 326 | When functions are added, the recommended minimum size might increase. 327 | 328 | 329 | ## Future 330 | 331 | #### Must 332 | 333 | - check TODO's in the code 334 | - documentation 335 | 336 | #### Should 337 | 338 | - improve readability of the code 339 | - em ==> exponentFactor? 340 | - extend unit tests 341 | 342 | #### Could 343 | 344 | - investigate **bin(float)** to dump floats? 345 | - "sign, mantissa, exponent bits" 346 | - like this "s0 m0111010 e100010" (right length) 347 | - investigate separators in **hex()** 348 | - space per 8, 4 or 2 349 | - investigate thread safe version 350 | - pass char buffer as parameter (breaking) 351 | - could be the log10 pow version? 352 | - optimize **char \* hex(uint8_t / uint16_t ...)** 353 | 354 | #### Wont 355 | 356 | - is there need for Scientific or Engineering integers (this just works) 357 | - add **oct()** along BIN, HEX 358 | - add **float()** as Arduino limits floats to "MAXLONG" by code. 359 | - use dtostrf() - is that portable? 360 | - use sci() or eng() 361 | - add **base(value, digits, base)** for any base > 1. 362 | - only upon request. 363 | - investigate separators in **bin()** 364 | - point or space, per 8 or 4 or 2 365 | - ==> printBuffer too small for bin(64) ==> need 75-100 bytes. 366 | - Investigate performance and accuracy 367 | - **sci()** and **eng()**. 368 | - investigate sci() version based upon use of log() 369 | - done => see examples. 370 | 371 | 372 | ## Support 373 | 374 | If you appreciate my libraries, you can support the development and maintenance. 375 | Improve the quality of the libraries by providing issues and Pull Requests, or 376 | donate through PayPal or GitHub sponsors. 377 | 378 | Thank you, 379 | 380 | -------------------------------------------------------------------------------- /examples/print64/print64.ino: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: print64.ino 3 | // AUTHOR: Rob Tillaart 4 | // PURPOSE: demo print 64 bit integers 5 | // URL: https://github.com/RobTillaart/printHelpers 6 | 7 | 8 | #include "printHelpers.h" 9 | 10 | 11 | uint64_t llx = 1311768467284833366; 12 | int64_t lly = 0xFFFFFFFFFFFFFFFF; 13 | uint64_t a = 0; 14 | 15 | uint32_t start, stop; 16 | 17 | 18 | void setup() 19 | { 20 | Serial.begin(115200); 21 | Serial.println(__FILE__); 22 | Serial.print("PRINTHELPERS_LIB_VERSION: "); 23 | Serial.println(PRINTHELPERS_LIB_VERSION); 24 | Serial.println(); 25 | 26 | delay(100); 27 | 28 | Serial.println("BASE\tTIME base < 10 support depends on internal buffer size"); 29 | for (uint8_t base = 2; base < 37; base++) 30 | { 31 | start = micros(); 32 | print64(llx, base); 33 | stop = micros(); 34 | Serial.print(base); 35 | Serial.print("\t"); 36 | Serial.print(stop - start); 37 | Serial.println(); 38 | delay(10); 39 | } 40 | 41 | Serial.println("\nsome numbers"); 42 | Serial.println("--------------"); 43 | Serial.println(print64(llx)); 44 | Serial.println(print64(a)); 45 | Serial.println(print64(llx, HEX)); 46 | Serial.println(print64(llx, 2)); 47 | Serial.println(print64(llx, 36)); 48 | Serial.println(print64(0xFFFFFFFFFFFFFFFF, 2)); 49 | Serial.println(print64(0xFFFFFFFFFFFFFFFF, 10)); 50 | Serial.println(print64(lly)); 51 | 52 | Serial.println("\ndone..."); 53 | } 54 | 55 | 56 | void loop() 57 | { 58 | } 59 | 60 | 61 | // -- END OF FILE -- 62 | 63 | -------------------------------------------------------------------------------- /examples/print_comma_separated_integers/print_comma_separated_integers.ino: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: print_comma_separated_integers.ino 3 | // AUTHOR: Rob Tillaart 4 | // PURPOSE: demo readability 5 | // URL: https://github.com/RobTillaart/printHelpers 6 | 7 | 8 | #include "printHelpers.h" 9 | 10 | 11 | void setup() 12 | { 13 | Serial.begin(115200); 14 | while (!Serial); 15 | Serial.println(__FILE__); 16 | Serial.print("PRINTHELPERS_LIB_VERSION: "); 17 | Serial.println(PRINTHELPERS_LIB_VERSION); 18 | 19 | Serial.println((int32_t)123456789); 20 | Serial.println(csi((int32_t)123456789)); 21 | Serial.println(csi((int32_t)-123456789)); 22 | Serial.println(csi((int32_t)12345678)); 23 | Serial.println(csi((uint32_t)1234567)); 24 | Serial.println(csi((int16_t)-12345)); 25 | Serial.println(csi((int16_t)1234)); 26 | Serial.println(csi((uint8_t)123)); 27 | Serial.println(csi((int8_t)12)); 28 | Serial.println(csi((int32_t)-1)); 29 | 30 | int64_t big = 123456789012345678; 31 | Serial.println(csi(big)); 32 | } 33 | 34 | void loop() 35 | { 36 | uint64_t large = 0; 37 | for (int i = 0; i < 64; i++) 38 | { 39 | large += random(2); 40 | large *= 2; 41 | } 42 | } 43 | 44 | // -- END OF FILE -- 45 | -------------------------------------------------------------------------------- /examples/print_fractions/print_fractions.ino: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: print_fractions.ino 3 | // AUTHOR: Rob Tillaart 4 | // PURPOSE: demo 5 | // URL: https://github.com/RobTillaart/printHelpers 6 | 7 | 8 | #include "printHelpers.h" 9 | 10 | uint32_t start, stop, duration; 11 | 12 | 13 | void setup() 14 | { 15 | Serial.begin(115200); 16 | Serial.println(__FILE__); 17 | Serial.print("PRINTHELPERS_LIB_VERSION: "); 18 | Serial.println(PRINTHELPERS_LIB_VERSION); 19 | Serial.println(); 20 | 21 | delay(100); 22 | start = micros(); 23 | char *p = fraction(-PI); 24 | stop = micros(); 25 | Serial.print("TIME: \t"); 26 | Serial.println(stop - start); 27 | Serial.println(p); 28 | delay(100); 29 | 30 | double n = 0.500; 31 | for (int i = 0; i <= 1000; i++) 32 | { 33 | Serial.print(i); 34 | Serial.print("\t"); 35 | Serial.print(n, 3); 36 | Serial.print("\t"); 37 | Serial.print(fraction(n)); 38 | Serial.println(); 39 | n += 0.001; 40 | } 41 | Serial.println(); 42 | 43 | Serial.println("\ndone..."); 44 | } 45 | 46 | 47 | void loop() 48 | { 49 | } 50 | 51 | 52 | // -- END OF FILE -- 53 | -------------------------------------------------------------------------------- /examples/print_fractions_denum/print_fractions_denum.ino: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: print_fractions_denum.ino 3 | // AUTHOR: Rob Tillaart 4 | // PURPOSE: demo 5 | // URL: https://github.com/RobTillaart/printHelpers 6 | 7 | 8 | #include "printHelpers.h" 9 | 10 | uint32_t start, stop, duration; 11 | 12 | 13 | void setup() 14 | { 15 | Serial.begin(115200); 16 | Serial.println(__FILE__); 17 | Serial.print("PRINTHELPERS_LIB_VERSION: "); 18 | Serial.println(PRINTHELPERS_LIB_VERSION); 19 | Serial.println(); 20 | 21 | delay(100); 22 | start = micros(); 23 | char *p = fraction(PI, 65536); // 2^16 24 | stop = micros(); 25 | Serial.print("TIME: \t"); 26 | Serial.println(stop - start); 27 | Serial.println(p); 28 | delay(100); 29 | 30 | start = micros(); 31 | p = fraction(EULER, 65536); // 2^16 32 | stop = micros(); 33 | Serial.print("TIME: \t"); 34 | Serial.println(stop - start); 35 | Serial.println(p); 36 | Serial.println(); 37 | delay(100); 38 | 39 | // notice most fractions will occur 3 or 4 times as denom 40 | // is smaller than the step size of n. 41 | double n = 0.500; 42 | for (int i = 0; i <= 1000; i++) 43 | { 44 | Serial.print(i); 45 | Serial.print("\t"); 46 | Serial.print(n, 3); 47 | Serial.print("\t"); 48 | Serial.print(fraction(n, 256)); 49 | Serial.println(); 50 | n += 0.001; 51 | } 52 | Serial.println(); 53 | 54 | Serial.println("\ndone..."); 55 | } 56 | 57 | 58 | void loop() 59 | { 60 | } 61 | 62 | 63 | // -- END OF FILE -- 64 | -------------------------------------------------------------------------------- /examples/print_hex_bin/print_hex_bin.ino: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: print_hex_bin.ino 3 | // AUTHOR: Rob Tillaart 4 | // PURPOSE: demo hex(value, sep); 5 | // URL: https://github.com/RobTillaart/printHelpers 6 | 7 | 8 | #include "printHelpers.h" 9 | 10 | 11 | volatile uint32_t n = 0; 12 | 13 | 14 | void setup() 15 | { 16 | Serial.begin(115200); 17 | Serial.println(); 18 | Serial.println(__FILE__); 19 | Serial.print("PRINTHELPERS_LIB_VERSION: "); 20 | Serial.println(PRINTHELPERS_LIB_VERSION); 21 | Serial.println(); 22 | 23 | Serial.println(); 24 | uint8_t a = 111; 25 | int8_t b = 112; 26 | uint16_t c = 113; 27 | int16_t d = 114; 28 | uint32_t e = 113; 29 | int32_t f = 114; 30 | Serial.print(hex(a)); 31 | Serial.print("\t"); 32 | Serial.println(bin(a)); 33 | 34 | Serial.print(hex((uint8_t)b)); 35 | Serial.print("\t"); 36 | Serial.println(bin((uint8_t)b)); 37 | 38 | Serial.print(hex(c)); 39 | Serial.print("\t"); 40 | Serial.println(bin(c)); 41 | 42 | Serial.print(hex((uint16_t)d)); 43 | Serial.print("\t"); 44 | Serial.println(bin((uint16_t)d)); 45 | 46 | Serial.print(hex(e)); 47 | Serial.print("\t"); 48 | Serial.println(bin(e)); 49 | 50 | Serial.print(hex((uint32_t)f)); 51 | Serial.print("\t"); 52 | Serial.println(bin((uint32_t)f)); 53 | 54 | Serial.println(hex((uint64_t)a)); 55 | Serial.println(bin((uint64_t)a)); 56 | 57 | 58 | Serial.println(); 59 | Serial.println("10 random() HEX values"); 60 | for (uint8_t i = 0; i < 10; i++) 61 | { 62 | n = 2 * random(2000000000) + random(2); // 0 .. 2^32-1 63 | Serial.print(n); 64 | Serial.print('\t'); 65 | Serial.print(hex(n)); 66 | Serial.print('\t'); 67 | Serial.println(n, HEX); 68 | } 69 | Serial.println(); 70 | 71 | Serial.println("10 random() BIN values"); 72 | for (uint8_t i = 0; i < 10; i++) 73 | { 74 | n = 2 * random(2000000000) + random(2); // 0 .. 2^32-1 75 | Serial.print(n); 76 | Serial.print('\t'); 77 | Serial.print(bin(n)); 78 | Serial.print('\t'); 79 | Serial.println(n, BIN); 80 | } 81 | Serial.println(); 82 | 83 | Serial.println("\ndone..."); 84 | } 85 | 86 | 87 | void loop() 88 | { 89 | } 90 | 91 | 92 | // -- END OF FILE -- 93 | -------------------------------------------------------------------------------- /examples/print_inch_feet/print_inch_feet.ino: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: print_inch_feet.ino 3 | // AUTHOR: Rob Tillaart 4 | // PURPOSE: demo program distance functions 5 | // URL: https://github.com/RobTillaart/printHelpers 6 | 7 | 8 | #include "printHelpers.h" 9 | 10 | 11 | void setup() 12 | { 13 | Serial.begin(115200); 14 | Serial.println(__FILE__); 15 | Serial.print("PRINTHELPERS_LIB_VERSION: "); 16 | Serial.println(PRINTHELPERS_LIB_VERSION); 17 | Serial.println(); 18 | 19 | // test some random values 20 | for (float inch = 0; inch < 100; inch += 5.43) 21 | { 22 | Serial.print(inch, 2); 23 | Serial.print('\t'); 24 | Serial.println(printInch(inch, 32)); 25 | } 26 | Serial.println(); 27 | 28 | 29 | for (float feet = 0; feet < 100; feet += 5.43) 30 | { 31 | Serial.print(feet, 2); 32 | Serial.print('\t'); 33 | Serial.println(printFeet(feet)); 34 | } 35 | } 36 | 37 | 38 | void loop() 39 | { 40 | } 41 | 42 | 43 | // -- END OF FILE -- 44 | -------------------------------------------------------------------------------- /examples/print_performance/performance_0.3.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Arduino UNO 3 | IDE 1.8.19 4 | 5 | print_sci_eng_performance.ino 6 | PRINTHELPERS_VERSION: 0.3.0 7 | 8 | 4 9 | 4 10 | 11 | Mass moon M = 7.34767309E+20 12 | Speed of light c = 2.99792458E+8 13 | Print E = Mc^2 = 6.6037592413026551656653076E+37 14 | 15 | 6.6037592887878417 16 | 17 | SCI 18 | TIME: 5076 19 | 6.603759288787841E+0 20 | 21 | ENG 22 | TIME: 5652 23 | 6.603759288787841E+0 24 | 25 | dtostrf 26 | TIME: 1784 27 | 6.603759300000000 28 | 29 | dtostre 30 | TIME: 1432 31 | 6.6037593e+00 32 | 33 | done... 34 | -------------------------------------------------------------------------------- /examples/print_performance/performance_0.3.1.txt: -------------------------------------------------------------------------------- 1 | 2 | Arduino UNO 3 | IDE 1.8.19 4 | 5 | print_performance.ino 6 | PRINTHELPERS_VERSION: 0.3.1 7 | 8 | 4 9 | 4 10 | 11 | Mass moon M = 7.34767309E+20 12 | Speed of light c = 2.99792458E+8 13 | Print E = Mc^2 = 6.6037592413026551656653076E+37 14 | 15 | 16 | 17 | print64 18 | TIME: 22476 19 | 660375892052148224 20 | 21 | SCI 22 | TIME: 8552 23 | 6.603759288787841E+17 24 | 25 | ENG 26 | TIME: 7580 27 | 660.375976562500000E+15 28 | 29 | dtostrf 30 | TIME: 2464 31 | 660375890000000000.000000000000000 32 | 33 | dtostre 34 | TIME: 1456 35 | 6.6037589e+17 36 | 37 | toBytes 38 | TIME: 2088 39 | 586.531 PB 40 | 41 | hex 42 | TIME: 1284 43 | 092A206000000000 44 | 45 | bin 46 | TIME: 2532 47 | 0000100100101010001000000110000000000000000000000000000000000000 48 | 49 | done... 50 | -------------------------------------------------------------------------------- /examples/print_performance/performance_0.4.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Arduino UNO 3 | IDE 1.8.19 4 | 5 | print_performance.ino 6 | PRINTHELPERS_VERSION: 0.4.0 7 | 8 | 4 9 | 4 10 | 11 | Mass moon M = 7.34767309E+20 12 | Speed of light c = 2.99792458E+8 13 | Print E = Mc^2 = 6.6037592413026551656653076E+37 14 | 15 | 16 | 17 | print64 18 | TIME: 22476 19 | 660375892052148224 20 | 21 | SCI 22 | TIME: 9236 23 | 6.603759288787841E+17 24 | 25 | ENG 26 | TIME: 7392 27 | 660.375976562500000E+15 28 | 29 | dtostrf 30 | TIME: 2464 31 | 660375890000000000.000000000000000 32 | 33 | dtostre 34 | TIME: 1456 35 | 6.6037589e+17 36 | 37 | toBytes 38 | TIME: 1980 39 | 586.531 PB 40 | 41 | hex 42 | TIME: 1276 43 | 092A206000000000 44 | 45 | bin 46 | TIME: 2464 47 | 0000100100101010001000000110000000000000000000000000000000000000 48 | 49 | toRoman 50 | TIME: 90164 51 | CMXCIX 52 | 53 | done... 54 | -------------------------------------------------------------------------------- /examples/print_performance/performance_0.4.1.txt: -------------------------------------------------------------------------------- 1 | 2 | Arduino UNO 3 | IDE 1.8.19 4 | 5 | print_performance.ino 6 | PRINTHELPERS_VERSION: 0.4.1 7 | 4 8 | 4 9 | 10 | Mass moon M = 7.34767309E+20 11 | Speed of light c = 2.99792458E+8 12 | Print E = Mc^2 = 6.6037592413026551656653076E+37 13 | 14 | 15 | 16 | print64 17 | TIME: 22476 18 | 660375892052148224 19 | 20 | SCI 21 | TIME: 9232 22 | 6.603759288787841E+17 23 | 24 | ENG 25 | TIME: 7388 26 | 660.375976562500000E+15 27 | 28 | dtostrf 29 | TIME: 2468 30 | 660375890000000000.000000000000000 31 | 32 | dtostre 33 | TIME: 1452 34 | 6.6037589e+17 35 | 36 | toBytes 37 | TIME: 1980 38 | 586.531 PB 39 | 40 | hex 41 | TIME: 1304 42 | 092A206000000000 43 | 44 | bin 45 | TIME: 2464 46 | 0000100100101010001000000110000000000000000000000000000000000000 47 | 48 | toRoman 49 | TIME: 89352 50 | CMXCIX 51 | 52 | printInch 53 | TIME: 177308 54 | 999 0/16 55 | 56 | printFeet 57 | TIME: 137448 58 | 999"0' 59 | 60 | done... 61 | -------------------------------------------------------------------------------- /examples/print_performance/performance_0.4.3.txt: -------------------------------------------------------------------------------- 1 | 2 | Arduino UNO 3 | IDE 1.8.19 4 | 5 | print_performance.ino 6 | D:\Rob\WORK\Arduino\libraries\printHelpers\examples\print_performance\print_performance.ino 7 | PRINTHELPERS_VERSION: 0.4.3 8 | 9 | 4 10 | 4 11 | 12 | Mass moon M = 7.34767309E+20 13 | Speed of light c = 2.99792458E+8 14 | Print E = Mc^2 = 6.6037592413026551656653076E+37 15 | 16 | 17 | 18 | print64 19 | TIME: 22476 20 | 660375892052148224 21 | 22 | SCI 23 | TIME: 9236 24 | 6.603759288787841E+17 25 | 26 | ENG 27 | TIME: 7388 28 | 660.375976562500000E+15 29 | 30 | dtostrf 31 | TIME: 2468 32 | 660375890000000000.000000000000000 33 | 34 | dtostre 35 | TIME: 1452 36 | 6.6037589e+17 37 | 38 | toBytes 39 | TIME: 1976 40 | 586.531 PB 41 | 42 | hex 43 | TIME: 1308 44 | 092A206000000000 45 | 46 | bin 47 | TIME: 2464 48 | 0000100100101010001000000110000000000000000000000000000000000000 49 | 50 | toRoman 51 | TIME: 89352 52 | CMXCIX 53 | 54 | printInch 55 | TIME: 177312 56 | 999 0/16 57 | 58 | printFeet 59 | TIME: 137448 60 | 999"0' 61 | 62 | CSI 63 | TIME: 3015752 64 | 1,234,567,890,987,654,321 65 | 1234567890987654321 66 | 67 | done... 68 | -------------------------------------------------------------------------------- /examples/print_performance/print_performance.ino: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: print_sci_eng_performance.ino 3 | // AUTHOR: Rob Tillaart 4 | // PURPOSE: demo program SCI 5 | // URL: https://github.com/RobTillaart/printHelpers 6 | 7 | 8 | #include "printHelpers.h" 9 | 10 | 11 | uint32_t start = 0; 12 | uint32_t stop = 0; 13 | char * b; 14 | 15 | 16 | void setup() 17 | { 18 | Serial.begin(115200); 19 | Serial.println(__FILE__); 20 | Serial.print("PRINTHELPERS_LIB_VERSION: "); 21 | Serial.println(PRINTHELPERS_LIB_VERSION); 22 | Serial.println(); 23 | 24 | Serial.println(sizeof(float)); 25 | Serial.println(sizeof(double)); 26 | 27 | 28 | double c = 2.99792458E8; // speed of light; 29 | double m = 7.34767309E20; // mass of moon 30 | double E = m * c * c; 31 | 32 | Serial.println(); 33 | Serial.println(" Mass moon M = 7.34767309E+20"); 34 | Serial.println("Speed of light c = 2.99792458E+8"); 35 | Serial.println(" Print E = Mc^2 = 6.6037592413026551656653076E+37 \n"); 36 | Serial.println(); 37 | 38 | E = 660375924130265516; 39 | 40 | // Serial.println(E, 16); 41 | Serial.println(); 42 | Serial.println("print64"); 43 | delay(100); 44 | start = micros(); 45 | for (int len = 0; len < 16; len++) 46 | { 47 | b = print64(int64_t(E), 10); 48 | } 49 | stop = micros(); 50 | Serial.print("TIME: "); 51 | Serial.println(stop - start); 52 | Serial.println(b); 53 | 54 | Serial.println(); 55 | Serial.println("SCI"); 56 | delay(100); 57 | start = micros(); 58 | for (int len = 0; len < 16; len++) 59 | { 60 | b = sci(E, len); 61 | } 62 | stop = micros(); 63 | Serial.print("TIME: "); 64 | Serial.println(stop - start); 65 | Serial.println(b); 66 | 67 | Serial.println(); 68 | Serial.println("ENG"); 69 | delay(100); 70 | start = micros(); 71 | for (int len = 0; len < 16; len++) 72 | { 73 | b = eng(E, len); 74 | } 75 | stop = micros(); 76 | Serial.print("TIME: "); 77 | Serial.println(stop - start); 78 | Serial.println(b); 79 | 80 | 81 | #if defined(__AVR__) 82 | Serial.println(); 83 | Serial.println("dtostrf"); 84 | delay(100); 85 | char buffer[200]; 86 | start = micros(); 87 | for (int len = 0; len < 16; len++) 88 | { 89 | dtostrf(E, 4, len, buffer); 90 | } 91 | stop = micros(); 92 | Serial.print("TIME: "); 93 | Serial.println(stop - start); 94 | Serial.println(buffer); 95 | delay(100); 96 | 97 | Serial.println(); 98 | Serial.println("dtostre"); 99 | delay(100); 100 | start = micros(); 101 | for (int len = 0; len < 16; len++) 102 | { 103 | dtostre(E, buffer, len, 0 ); 104 | } 105 | stop = micros(); 106 | Serial.print("TIME: "); 107 | Serial.println(stop - start); 108 | Serial.println(buffer); 109 | delay(100); 110 | #endif 111 | 112 | 113 | Serial.println(); 114 | Serial.println("toBytes"); 115 | delay(100); 116 | start = micros(); 117 | for (int len = 0; len < 16; len++) 118 | { 119 | b = toBytes(E, len); 120 | } 121 | stop = micros(); 122 | Serial.print("TIME: "); 123 | Serial.println(stop - start); 124 | Serial.println(b); 125 | delay(100); 126 | 127 | Serial.println(); 128 | Serial.println("hex"); 129 | delay(100); 130 | start = micros(); 131 | for (int len = 0; len < 16; len++) 132 | { 133 | b = hex(uint64_t(E)); 134 | } 135 | stop = micros(); 136 | Serial.print("TIME: "); 137 | Serial.println(stop - start); 138 | Serial.println(b); 139 | delay(100); 140 | 141 | Serial.println(); 142 | Serial.println("bin"); 143 | delay(100); 144 | start = micros(); 145 | for (int len = 0; len < 16; len++) 146 | { 147 | b = bin(uint64_t(E)); 148 | } 149 | stop = micros(); 150 | Serial.print("TIME: "); 151 | Serial.println(stop - start); 152 | Serial.println(b); 153 | delay(100); 154 | 155 | 156 | Serial.println(); 157 | Serial.println("toRoman"); 158 | delay(100); 159 | start = micros(); 160 | for (int i = 0; i < 1000; i++) 161 | { 162 | b = toRoman(i); 163 | } 164 | stop = micros(); 165 | Serial.print("TIME: "); 166 | Serial.println(stop - start); 167 | Serial.println(b); 168 | delay(100); 169 | 170 | 171 | Serial.println(); 172 | Serial.println("printInch"); 173 | delay(100); 174 | start = micros(); 175 | for (int i = 0; i < 1000; i++) 176 | { 177 | b = printInch(i); 178 | } 179 | stop = micros(); 180 | Serial.print("TIME: "); 181 | Serial.println(stop - start); 182 | Serial.println(b); 183 | delay(100); 184 | 185 | 186 | Serial.println(); 187 | Serial.println("printFeet"); 188 | delay(100); 189 | start = micros(); 190 | for (int i = 0; i < 1000; i++) 191 | { 192 | b = printFeet(i); 193 | } 194 | stop = micros(); 195 | Serial.print("TIME: "); 196 | Serial.println(stop - start); 197 | Serial.println(b); 198 | delay(100); 199 | 200 | 201 | Serial.println(); 202 | Serial.println("CSI"); 203 | volatile uint64_t big = 1234567890987654321; 204 | delay(100); 205 | start = micros(); 206 | for (int i = 0; i < 1000; i++) 207 | { 208 | b = csi(big); 209 | } 210 | stop = micros(); 211 | Serial.print("TIME: "); 212 | Serial.println(stop - start); 213 | Serial.println(csi(big)); 214 | Serial.println(print64(big)); 215 | delay(100); 216 | 217 | 218 | Serial.println(); 219 | Serial.println("done..."); 220 | } 221 | 222 | 223 | void loop() 224 | { 225 | } 226 | 227 | 228 | // -- END OF FILE -- 229 | -------------------------------------------------------------------------------- /examples/print_sci/print_sci.ino: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: print_sci.ino 3 | // AUTHOR: Rob Tillaart 4 | // PURPOSE: demo program SCI 5 | // URL: https://github.com/RobTillaart/printHelpers 6 | 7 | 8 | #include "printHelpers.h" 9 | 10 | 11 | void setup() 12 | { 13 | Serial.begin(115200); 14 | Serial.println(__FILE__); 15 | Serial.print("PRINTHELPERS_LIB_VERSION: "); 16 | Serial.println(PRINTHELPERS_LIB_VERSION); 17 | Serial.println(); 18 | 19 | Serial.println(sizeof(float)); 20 | Serial.println(sizeof(double)); 21 | 22 | 23 | double c = 2.99792458E8; // speed of light; 24 | double m = 7.34767309E20; // mass of moon 25 | double E = m * c * c; 26 | 27 | Serial.println(); 28 | Serial.println(" Mass moon M = 7.34767309E+20"); 29 | Serial.println("Speed of light c = 2.99792458E+8"); 30 | Serial.println(" Print E = Mc^2 = 6.6037592413026551656653076E+37 \n"); 31 | 32 | Serial.print(" normal print:\t"); 33 | Serial.println(E, 4); 34 | Serial.println("Cannot handle floats / doubles > MAXLONG\n"); 35 | 36 | 37 | #if defined(ARDUINO_ARCH_AVR) 38 | char buffer[200]; 39 | Serial.print("dtostrf print:\t"); 40 | Serial.println(dtostrf(E, 4, 4, buffer)); 41 | Serial.println("Has no scientific notation\n"); 42 | 43 | Serial.print("dtostre print:\t"); 44 | Serial.println(dtostre(E, buffer, 4, 0 )); 45 | Serial.print("dtostre print:\t"); 46 | Serial.println(dtostre(E, buffer, 16, 0 )); 47 | Serial.println("Limited to 7 decimals\n"); 48 | #endif 49 | 50 | 51 | Serial.print(" sci print:\t"); 52 | Serial.println(sci(E, 4)); 53 | Serial.print(" sci print:\t"); 54 | Serial.println(sci(E, 16)); 55 | Serial.println("limited only by precision float\n"); 56 | 57 | 58 | Serial.print(" eng print:\t"); 59 | Serial.println(eng(E, 4)); 60 | Serial.print(" eng print:\t"); 61 | Serial.println(eng(E, 16)); 62 | Serial.println("limited only by precision float\n"); 63 | 64 | 65 | E /= 100; // more interesting effect 66 | Serial.println("scieng() is not meant to use directly"); 67 | Serial.println("it works well up exponent multiple of 1..9"); 68 | Serial.println("some values for em have their esthetics too.\n"); 69 | for (int em = 1; em < 10; em++) 70 | { 71 | Serial.print(em); 72 | Serial.print("\t"); 73 | Serial.println(scieng(E, 8, em)); 74 | } 75 | Serial.println(); 76 | 77 | if (sizeof(double) == 8) 78 | { 79 | while (E < 1e308) 80 | { 81 | E *= 1e5; 82 | Serial.println(sci(E, 16)); 83 | } 84 | } 85 | 86 | Serial.println("\ndone..."); 87 | } 88 | 89 | 90 | void loop() 91 | { 92 | } 93 | 94 | 95 | // -- END OF FILE -- 96 | 97 | -------------------------------------------------------------------------------- /examples/print_sci_experimental/print_sci_experimental.ino: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: print_sci_experimental.ino 3 | // AUTHOR: Rob Tillaart 4 | // PURPOSE: test program SCI 5 | // URL: https://github.com/RobTillaart/printHelpers 6 | 7 | 8 | #include "printHelpers.h" 9 | 10 | uint32_t start, stop, duration; 11 | 12 | 13 | void setup() 14 | { 15 | Serial.begin(115200); 16 | Serial.println(__FILE__); 17 | Serial.print("PRINTHELPERS_LIB_VERSION: "); 18 | Serial.println(PRINTHELPERS_LIB_VERSION); 19 | Serial.println(); 20 | 21 | Serial.print("FLOAT: \t"); 22 | Serial.println(sizeof(float)); 23 | Serial.print("DOUBLE: \t"); 24 | Serial.println(sizeof(double)); 25 | Serial.println(); 26 | 27 | double n = 6.072832E+37; 28 | 29 | // reference 30 | Serial.println("TEXT: \t6.072832E+37"); 31 | Serial.print("PRINT: \t"); 32 | Serial.println(n); 33 | Serial.println(); 34 | 35 | 36 | delay(100); 37 | start = micros(); 38 | char * b = sci(n, 6); 39 | stop = micros(); 40 | Serial.print("TIME: \t"); 41 | Serial.println(stop - start); 42 | Serial.print("SCI: \t"); 43 | Serial.println(b); 44 | delay(100); 45 | // duration = stop - start; 46 | 47 | start = micros(); 48 | b = newsci(n, 6); 49 | stop = micros(); 50 | Serial.print("TIME: \t"); 51 | Serial.println(stop - start); 52 | // Serial.println((stop - start) *1.0 / duration); 53 | Serial.print("NEWSCI: \t"); 54 | Serial.println(b); 55 | delay(100); 56 | 57 | Serial.println(); 58 | Serial.println(); 59 | n = PI; 60 | 61 | for (int i = 0; i < 75; i++) 62 | { 63 | Serial.print(i); 64 | Serial.print("\t"); 65 | Serial.print(sci(n, 6)); 66 | Serial.print("\t"); 67 | Serial.print(newsci(n, 6)); 68 | Serial.println(); 69 | n *= PI; 70 | } 71 | Serial.println(); 72 | 73 | Serial.println("\ndone..."); 74 | } 75 | 76 | 77 | char * newsci(double n, uint8_t decimals) 78 | { 79 | static char buffer[20]; 80 | if (isnan(n)) 81 | { 82 | strcpy(buffer, "nan"); 83 | return buffer; 84 | } 85 | if (isinf(n)) 86 | { 87 | if (n < 0) strcpy(buffer, "-inf"); 88 | strcpy(buffer, "inf"); 89 | return buffer; 90 | } 91 | bool neg = (n < 0); 92 | if (neg) 93 | { 94 | n = -n; 95 | } 96 | // int exponent = int(log(n) * (1.0 / log(10))); 97 | int exponent = int(log10(n)); 98 | double factor = pow(10, -exponent); 99 | double mantissa = n * factor; 100 | if (mantissa < 1) 101 | { 102 | mantissa *= 10; 103 | exponent--; 104 | } 105 | int mantInt = mantissa; 106 | long mantDec = (mantissa - mantInt) * pow(10, decimals); 107 | if (neg) 108 | { 109 | mantInt = -mantInt; 110 | } 111 | 112 | char format[24]; 113 | sprintf(format, "%%d.%%0%dldE%%+02d", decimals); 114 | 115 | sprintf(buffer, format, mantInt, mantDec, exponent); 116 | // sprintf(buffer, "%d.%06ldE%+02d", mantInt, mantDec, exponent); 117 | return buffer; 118 | } 119 | 120 | 121 | void loop() 122 | { 123 | } 124 | 125 | 126 | // -- END OF FILE -- 127 | -------------------------------------------------------------------------------- /examples/print_toRoman/print_toRoman.ino: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: print_toRoman.ino 3 | // AUTHOR: Rob Tillaart 4 | // PURPOSE: demo program toRoman 5 | // URL: https://github.com/RobTillaart/printHelpers 6 | 7 | 8 | #include "printHelpers.h" 9 | 10 | uint32_t start, stop; 11 | 12 | 13 | void setup() 14 | { 15 | Serial.begin(115200); 16 | Serial.println(__FILE__); 17 | Serial.print("PRINTHELPERS_LIB_VERSION: "); 18 | Serial.println(PRINTHELPERS_LIB_VERSION); 19 | Serial.println(); 20 | 21 | Serial.println(sizeof(float)); 22 | Serial.println(sizeof(double)); 23 | 24 | uint8_t maxlen = 0; 25 | 26 | for (uint32_t i = 1; i <= 5000; i++) 27 | { 28 | uint8_t len = strlen(toRoman(i)); 29 | if (maxlen < len) 30 | { 31 | maxlen = len; 32 | Serial.print(i); 33 | Serial.print("\t"); 34 | Serial.println(toRoman(i)); 35 | } 36 | } 37 | Serial.println(); 38 | Serial.print("MAXLEN: "); 39 | Serial.println(maxlen); 40 | Serial.println(); 41 | delay(1000); 42 | 43 | start = micros(); 44 | char * b; 45 | for (int i = 1; i <= 5000; i++) 46 | { 47 | b = toRoman(i); 48 | } 49 | stop = micros(); 50 | Serial.println((stop - start) / 5000.0); 51 | Serial.println(b); 52 | delay(100); 53 | 54 | // unofficial romans 55 | start = micros(); 56 | b = toRoman(12345678); 57 | stop = micros(); 58 | Serial.println(); 59 | Serial.println(stop - start); 60 | Serial.println(b); 61 | delay(100); 62 | 63 | // for (int i = 1; i <= 5000; i++) 64 | // { 65 | // Serial.print(i); 66 | // Serial.print('\t'); 67 | // Serial.println(toRoman(i)); 68 | // } 69 | // delay(1000); 70 | 71 | Serial.println("\ndone..."); 72 | } 73 | 74 | 75 | void loop() 76 | { 77 | } 78 | 79 | // -- END OF FILE -- 80 | -------------------------------------------------------------------------------- /examples/sci_test/sci_test.ino: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: sci_test.ino 3 | // AUTHOR: Rob Tillaart 4 | // PURPOSE: test different values with sci function 5 | // URL: https://github.com/RobTillaart/printHelpers 6 | 7 | 8 | #include "printHelpers.h" 9 | 10 | uint32_t start, stop; 11 | 12 | 13 | void setup() 14 | { 15 | Serial.begin(115200); 16 | Serial.println(__FILE__); 17 | Serial.print("PRINTHELPERS_LIB_VERSION: "); 18 | Serial.println(PRINTHELPERS_LIB_VERSION); 19 | Serial.println(); 20 | 21 | test1(); 22 | test2(); 23 | test3(); 24 | test4(); 25 | test5(); 26 | test6(); 27 | 28 | Serial.println("\nDone..."); 29 | } 30 | 31 | 32 | void loop() 33 | { 34 | } 35 | 36 | 37 | void test1() 38 | { 39 | Serial.println(); 40 | Serial.println(__FUNCTION__); 41 | 42 | double f = 1; 43 | for (int i = 0; i < 40; i++) 44 | { 45 | f *= 10; 46 | Serial.println(sci(f, 6)); 47 | } 48 | Serial.println(); 49 | 50 | f = 1; 51 | for (int i = 0; i < 50; i++) 52 | { 53 | f /= 10; 54 | Serial.println(sci(f, 6)); 55 | } 56 | Serial.println(); 57 | 58 | f = -1; 59 | for (int i = 0; i < 40; i++) 60 | { 61 | f *= 10; 62 | Serial.println(sci(f, 6)); 63 | } 64 | Serial.println(); 65 | 66 | f = -1; 67 | for (int i = 0; i < 50; i++) 68 | { 69 | f /= 10; 70 | Serial.println(sci(f, 6)); 71 | } 72 | Serial.println(); 73 | Serial.println(); 74 | } 75 | 76 | 77 | void test2() 78 | { 79 | Serial.println(); 80 | Serial.println(__FUNCTION__); 81 | 82 | double f = 1; 83 | for (int i = 0; i < 40; i++) 84 | { 85 | f *= (PI * PI); 86 | Serial.println(sci(f, 6)); 87 | } 88 | Serial.println(); 89 | f = 1; 90 | for (int i = 0; i < 50; i++) 91 | { 92 | f /= (PI * PI); 93 | Serial.println(sci(f, 6)); 94 | } 95 | Serial.println(); 96 | f = -1; 97 | for (int i = 0; i < 40; i++) 98 | { 99 | f *= (PI * PI); 100 | Serial.println(sci(f, 6)); 101 | } 102 | Serial.println(); 103 | f = -1; 104 | for (int i = 0; i < 50; i++) 105 | { 106 | f /= (PI * PI); 107 | Serial.println(sci(f, 6)); 108 | } 109 | Serial.println(); 110 | Serial.println(); 111 | } 112 | 113 | 114 | void test3() 115 | { 116 | Serial.println(); 117 | Serial.println(__FUNCTION__); 118 | 119 | double f = PI; 120 | for (int digits = 0; digits < 15; digits++) 121 | { 122 | Serial.println(sci(f, digits)); 123 | } 124 | Serial.println(); 125 | } 126 | 127 | 128 | void test4() 129 | { 130 | Serial.println(); 131 | Serial.println(__FUNCTION__); 132 | 133 | double f = PI; 134 | for (int digits = 0; digits < 15; digits++) 135 | { 136 | sci(Serial, f, digits); 137 | Serial.println(); 138 | } 139 | Serial.println(); 140 | } 141 | 142 | 143 | void test5() 144 | { 145 | Serial.println(); 146 | Serial.println(__FUNCTION__); 147 | 148 | double f = 1.0 / 0.0; 149 | Serial.println(sci(f, 6)); 150 | f = 0.0 / 0.0; 151 | Serial.println(sci(f, 6)); 152 | f = -1.0 / 0.0; 153 | Serial.println(sci(f, 6)); 154 | // TODO find a -inf 155 | Serial.println(sci(tan(PI / 2), 6)); 156 | Serial.println(); 157 | } 158 | 159 | 160 | void test6() 161 | { 162 | if (sizeof(double) >= 8) 163 | { 164 | Serial.println("DEC\tTIME\tVALUE"); 165 | for (int i = 0; i < 16; i++) 166 | { 167 | double f = PI * 1E307; // causes warning... 168 | start = micros(); 169 | char * b = sci(f, i); 170 | stop = micros(); 171 | Serial.print(i); 172 | Serial.print('\t'); 173 | Serial.print(stop - start); 174 | Serial.print('\t'); 175 | Serial.print(b); 176 | Serial.println(); 177 | delay(10); 178 | } 179 | Serial.println(); 180 | } 181 | 182 | // floats 183 | Serial.println("DEC\tTIME\tVALUE"); 184 | for (int i = 0; i < 16; i++) 185 | { 186 | double f = PI * 1E38; 187 | start = micros(); 188 | char * b = sci(f, i); 189 | stop = micros(); 190 | Serial.print(i); 191 | Serial.print('\t'); 192 | Serial.print(stop - start); 193 | Serial.print('\t'); 194 | Serial.print(b); 195 | Serial.println(); 196 | delay(10); 197 | } 198 | } 199 | 200 | 201 | // -- END OF FILE -- 202 | 203 | -------------------------------------------------------------------------------- /examples/toBytes/toBytes.ino: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: toBytes.ino 3 | // AUTHOR: Rob Tillaart 4 | // PURPOSE: demo toBytes(double val); 5 | // URL: https://github.com/RobTillaart/printHelpers 6 | 7 | 8 | #include "printHelpers.h" 9 | 10 | volatile uint32_t n = 0; 11 | 12 | 13 | void setup() 14 | { 15 | Serial.begin(115200); 16 | Serial.println(__FILE__); 17 | Serial.print("PRINTHELPERS_LIB_VERSION: "); 18 | Serial.println(PRINTHELPERS_LIB_VERSION); 19 | Serial.println(); 20 | 21 | delay(100); 22 | 23 | Serial.println("20 random() values"); 24 | for (uint8_t i = 0; i < 20; i++) 25 | { 26 | n = random(PI * pow(10, i)); 27 | Serial.print(i); 28 | Serial.print('\t'); 29 | Serial.print(sci(n, 3)); 30 | Serial.print('\t'); 31 | Serial.print(toBytes(n)); 32 | Serial.print('\t'); 33 | Serial.println(); 34 | } 35 | Serial.println(); 36 | 37 | Serial.println("20 BIG values"); 38 | double n = PI * 12345; 39 | for (uint8_t i = 0; i < 20; i++) 40 | { 41 | Serial.print(i); 42 | Serial.print('\t'); 43 | Serial.print(sci(n, 3)); 44 | Serial.print('\t'); 45 | Serial.print(toBytes(n)); 46 | Serial.print('\t'); 47 | Serial.println(); 48 | n = n * (PI * PI * PI * PI); 49 | } 50 | Serial.println("\ndone..."); 51 | } 52 | 53 | 54 | void loop() 55 | { 56 | } 57 | 58 | 59 | // -- END OF FILE -- 60 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | # Syntax Colouring Map for printHelpers 2 | 3 | # Data types (KEYWORD1) 4 | 5 | 6 | # Methods and Functions (KEYWORD2) 7 | print64 KEYWORD2 8 | 9 | sci KEYWORD2 10 | eng KEYWORD2 11 | scieng KEYWORD2 12 | 13 | toBytes KEYWORD2 14 | 15 | hex KEYWORD2 16 | bin KEYWORD2 17 | 18 | toRoman KEYWORD2 19 | 20 | printInch KEYWORD2 21 | printFeet KEYWORD2 22 | 23 | csi KEYWORD2 24 | 25 | fraction KEYWORD2 26 | 27 | 28 | # Constants (LITERAL1) 29 | PRINTHELPERS_LIB_VERSION LITERAL1 30 | 31 | PRINTBUFFERSIZE LITERAL1 32 | 33 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "printHelpers", 3 | "keywords": "Convert,int64,uint64,print,scientific,notation,toBytes,HEX,BIN,Roman", 4 | "description": "Arduino library to help printing. int64 and uint64 support base 10 (DEC) and 16 (HEX). Scientific notation of floats. Feet and inch. Comma separated integers. Fractions.", 5 | "authors": 6 | [ 7 | { 8 | "name": "Rob Tillaart", 9 | "email": "Rob.Tillaart@gmail.com", 10 | "maintainer": true 11 | } 12 | ], 13 | "repository": 14 | { 15 | "type": "git", 16 | "url": "https://github.com/RobTillaart/printHelpers" 17 | }, 18 | "version": "0.4.6", 19 | "license": "MIT", 20 | "frameworks": "*", 21 | "platforms": "*", 22 | "headers": "printHelpers.h" 23 | } 24 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=printHelpers 2 | version=0.4.6 3 | author=Rob Tillaart 4 | maintainer=Rob Tillaart 5 | sentence=Arduino library to help formatting data for printing. 64 bit integers (base 10 and 16). Engineering and scientific notation. 6 | paragraph=Supports 64 bit integers (base 10 and 16). Engineering and scientific notation. toBytes() for KB MB, HEX and BIN, Roman numbers. Feet and inch. Comma separated integers. Fractions. 7 | category=Other 8 | url=https://github.com/RobTillaart/printHelpers 9 | architectures=* 10 | includes=printHelpers.h 11 | depends= 12 | -------------------------------------------------------------------------------- /printHelpers.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: printHelpers.cpp 3 | // AUTHOR: Rob Tillaart 4 | // DATE: 2018-01-21 5 | // VERSION: 0.4.6 6 | // PURPOSE: Arduino library to help formatting for printing. 7 | // URL: https://github.com/RobTillaart/printHelpers 8 | 9 | 10 | #include "printHelpers.h" 11 | 12 | 13 | // global buffer used by all functions so no static buffer in every function 14 | // is needed ==> results need to be printed/copied asap 15 | // not usable in multi-threading environments (use with care) 16 | // 17 | // 24 is a pretty safe minimum 18 | char __printbuffer[PRINTBUFFERSIZE]; 19 | 20 | 21 | //////////////////////////////////////////////////////////// 22 | // 23 | // PRINT 64 BIT 24 | // 25 | 26 | // print64 note 27 | // buffer size 66 will work for base 2 -36 28 | // buffer size 34 will work for base 4 -36 29 | // buffer size 24 will work for base 8 -36 30 | // buffer size 22 will work for base 10 - 36 31 | 32 | char * print64(int64_t value, uint8_t base) 33 | { 34 | char * buffer = __printbuffer; 35 | uint8_t i = 0; 36 | uint8_t j = 0; 37 | 38 | buffer[0] = 0; 39 | // small base need bigger buffer 40 | if ((base < 10) && (PRINTBUFFERSIZE <= 22)) return buffer; 41 | // handle special case 42 | if (value == 0) 43 | { 44 | buffer[0] = '0'; 45 | buffer[1] = 0; 46 | return buffer; 47 | } 48 | 49 | // PREFIX NEGATIVE 50 | // handle negative values (for all bases for now) 51 | if ((value < 0) && (base != 16)) 52 | { 53 | value = -value; 54 | buffer[0] = '-'; 55 | i++; 56 | j++; 57 | } 58 | 59 | // PREFIX HEX 60 | if (base == 16) 61 | { 62 | buffer[0] = '0'; 63 | buffer[1] = 'x'; 64 | buffer[2] = 0; 65 | i = 2; 66 | j = 2; 67 | } 68 | // create one digit per loop 69 | while (value > 0) 70 | { 71 | int64_t temp = value / base; 72 | uint8_t digit = value - temp * base; 73 | buffer[i++] = (digit < 10) ? '0' + digit : ('A' - 10) + digit; 74 | value = temp; 75 | } 76 | buffer[i] = 0; 77 | // reverse buffer 78 | --i; 79 | while ( i > j) 80 | { 81 | uint8_t temp = buffer[i]; 82 | buffer[i] = buffer[j]; 83 | buffer[j] = temp; 84 | i--; 85 | j++; 86 | } 87 | return buffer; 88 | } 89 | 90 | 91 | char * print64(uint64_t value, uint8_t base) 92 | { 93 | char * buffer = __printbuffer; 94 | uint8_t i = 0; 95 | uint8_t j = 0; 96 | 97 | buffer[0] = 0; 98 | // small base need bigger buffer 99 | if ((base < 10) && (PRINTBUFFERSIZE <= 22)) return buffer; 100 | // handle special case 101 | if (value == 0) 102 | { 103 | buffer[0] = '0'; 104 | buffer[1] = 0; 105 | return buffer; 106 | } 107 | // create one digit per iteration 108 | while (value > 0) 109 | { 110 | uint64_t temp = value / base; 111 | uint8_t digit = value - temp * base; 112 | buffer[i++] = (digit < 10) ? '0' + digit : ('A' - 10) + digit; 113 | value = temp; 114 | } 115 | buffer[i] = 0; 116 | // reverse buffer 117 | --i; 118 | while (i > j) 119 | { 120 | uint8_t temp = buffer[i]; 121 | buffer[i] = buffer[j]; 122 | buffer[j] = temp; 123 | i--; 124 | j++; 125 | } 126 | return buffer; 127 | } 128 | 129 | 130 | //////////////////////////////////////////////////////////// 131 | // 132 | // SCIENTIFIC NOTATIION 133 | // 134 | 135 | // typical buffer size for 8 byte double is 22 bytes 136 | // 15 bytes mantissa, sign dot E-xxx 137 | // em = exponentMultiple == step size exponent. 138 | char * scieng(double value, uint8_t decimals, uint8_t em) 139 | { 140 | char * buffer = __printbuffer; 141 | int exponent = 0; 142 | uint8_t pos = 0; 143 | double e1 = 10; // exponent step > 1 144 | double e2 = 0.1; // exponent step < 1 145 | 146 | // scale to multiples of em. 147 | for (uint8_t i = 1; i < em; i++) 148 | { 149 | e1 *= 10; 150 | e2 *= 0.1; 151 | } 152 | 153 | // Handling these costs 13 bytes RAM 154 | // shorten them with N, I, -I ? 155 | if (isnan(value)) 156 | { 157 | strcpy(buffer, "nan"); 158 | return buffer; 159 | } 160 | if (isinf(value)) 161 | { 162 | if (value < 0) strcpy(buffer, "-inf"); 163 | strcpy(buffer, "inf"); 164 | return buffer; 165 | } 166 | 167 | // Handle negative numbers 168 | if (value < 0.0) 169 | { 170 | buffer[pos++] = '-'; 171 | value = -value; 172 | } 173 | 174 | // Scale exponent to multiple of em 175 | // TODO: can we remove loop to reduce rounding errors 176 | while (value >= e1) 177 | { 178 | value *= e2; 179 | exponent += em; 180 | } 181 | // TODO: can we remove loop to reduce rounding errors 182 | while (value < 1 && value != 0.0) 183 | { 184 | value *= e1; 185 | exponent -= em; 186 | } 187 | 188 | // Round correctly so that print(1.999, 2) prints as "2.00" 189 | double rounding = 0.5; 190 | // TODO: can we remove loop to reduce rounding errors? 191 | // additional loop that steps per 1000? 192 | for (uint8_t i = 0; i < decimals; ++i) 193 | { 194 | rounding *= 0.1; 195 | } 196 | value += rounding; 197 | if (value >= e1) 198 | { 199 | exponent += em; 200 | value *= e2; 201 | } 202 | 203 | // Split whole part and remainder 204 | uint32_t d = (uint32_t)value; 205 | double remainder = value - d; 206 | 207 | 208 | // print whole part 209 | #if defined(ESP32) 210 | // ESP32 does not support %ld or ltoa() 211 | itoa(d, &buffer[pos], 10); 212 | #else 213 | sprintf(&buffer[pos], "%ld", d); 214 | #endif 215 | pos = strlen(buffer); 216 | 217 | 218 | // print remainder part 219 | if (decimals > 0) 220 | { 221 | buffer[pos++] = '.'; // decimal point 222 | } 223 | 224 | // Extract decimals from the remainder one at a time 225 | // to prevent missing leading zero's 226 | while (decimals-- > 0) 227 | { 228 | remainder *= 10; 229 | d = (uint8_t)remainder; 230 | buffer[pos++] = d + '0'; 231 | remainder -= d; 232 | } 233 | 234 | // print exponent 235 | buffer[pos++] = 'E'; 236 | if (exponent < 0) 237 | { 238 | buffer[pos++] = '-'; 239 | exponent = -exponent; 240 | } 241 | else buffer[pos++] = '+'; 242 | 243 | if (exponent < 10) buffer[pos++] = '0'; 244 | itoa(exponent, &buffer[pos], 10); 245 | return buffer; 246 | } 247 | 248 | 249 | char * eng(double value, uint8_t decimals) 250 | { 251 | return scieng(value, decimals, 3); 252 | } 253 | 254 | 255 | char * sci(double value, uint8_t decimals) 256 | { 257 | return scieng(value, decimals, 1); 258 | } 259 | 260 | 261 | size_t sci(Stream &str, double value, uint8_t decimals) 262 | { 263 | return str.print(sci(value, decimals)); 264 | } 265 | 266 | 267 | //////////////////////////////////////////////////////////// 268 | // 269 | // toBytes 270 | // 271 | 272 | // official support to UDA == 1024^12 273 | // kilo mega giga tera peta exa (1024^6) 274 | // zetta yotta xona weka vunda uda (1024^12) 275 | // 276 | // (treda Byte == TDB is the next one and it is 2 char 277 | // so code wise difficult and as it is seldom used, support stops there. 278 | // 279 | // To have some support the code uses lowercase for the next 8 levels 280 | // treda sorta rinta quexa pepta ocha nena minga luma (1024 ^13 ~~ 1024^21) 281 | // 282 | char * toBytes(double value, uint8_t decimals) 283 | { 284 | char * buffer = __printbuffer; 285 | // to enable full range uncomment the following line 286 | // char units[] = " KMGTPEZYXWVUtsrqponml"; 287 | 288 | char units[] = " KMGTPEZYXWVU"; 289 | uint8_t i = 0; // i is index of the unit array == powers of 1024. 290 | 291 | if (isinf(value)) 292 | { 293 | strcpy(buffer, ""); 294 | return buffer; 295 | } 296 | 297 | while(value >= 1024) 298 | { 299 | value /= 1024; 300 | i++; 301 | } 302 | if (i == 0) decimals = 0; 303 | if (decimals > 3) decimals = 3; 304 | 305 | // WHOLE PART iv 306 | int integerPart = value; 307 | itoa(integerPart, &buffer[0], 10); 308 | 309 | // DECIMALS 310 | value -= integerPart; 311 | uint8_t pos = strlen(buffer); 312 | if (decimals > 0) 313 | { 314 | buffer[pos++] = '.'; 315 | while (decimals-- > 0) 316 | { 317 | value = value * 10; 318 | buffer[pos++] = '0' + int(value); 319 | value -= int(value); 320 | } 321 | } 322 | 323 | // UNITS 324 | if (i <= strlen(units)) 325 | { 326 | if (i > 0) buffer[pos++] = ' '; 327 | buffer[pos++] = units[i]; 328 | buffer[pos++] = 'B'; 329 | buffer[pos] = 0; 330 | } 331 | else 332 | { 333 | // no units available 334 | } 335 | return buffer; 336 | } 337 | 338 | 339 | //////////////////////////////////////////////////////////// 340 | // 341 | // HEX 342 | // 343 | // always leading zero's - no prefix - no separator 344 | char * hex(uint64_t value, uint8_t digits) 345 | { 346 | uint64_t val = value; 347 | char * buffer = __printbuffer; 348 | buffer[digits] = '\0'; 349 | while (digits > 0) 350 | { 351 | uint8_t v = val & 0x0F; 352 | val >>= 4; 353 | digits--; 354 | buffer[digits] = (v < 10) ? '0' + v : ('A' - 10) + v; 355 | } 356 | return buffer; 357 | } 358 | 359 | // faster than 64 bit. 360 | char * hex(uint32_t value, uint8_t digits) 361 | { 362 | uint32_t val = value; 363 | char * buffer = __printbuffer; 364 | buffer[digits] = '\0'; 365 | while (digits > 0) 366 | { 367 | uint8_t v = val & 0x0F; 368 | val >>= 4; 369 | digits--; 370 | buffer[digits] = (v < 10) ? '0' + v : ('A' - 10) + v; 371 | } 372 | return buffer; 373 | } 374 | 375 | char * hex(uint16_t value, uint8_t digits) { return hex((uint32_t) value, digits); }; 376 | char * hex(uint8_t value, uint8_t digits) { return hex((uint32_t) value, digits); }; 377 | 378 | 379 | //////////////////////////////////////////////////////////// 380 | // 381 | // BIN 382 | // 383 | // always leading zero's - no prefix - no separator 384 | char * bin(uint64_t value, uint8_t digits) 385 | { 386 | uint64_t val = value; 387 | char * buffer = __printbuffer; 388 | buffer[digits] = '\0'; 389 | while (digits > 0) 390 | { 391 | digits--; 392 | buffer[digits] = '0' + (val & 1); 393 | val >>= 1; 394 | } 395 | return buffer; 396 | } 397 | 398 | // faster than 64 bit. 399 | char * bin(uint32_t value, uint8_t digits) 400 | { 401 | uint64_t val = value; 402 | char * buffer = __printbuffer; 403 | buffer[digits] = '\0'; 404 | while (digits > 0) 405 | { 406 | digits--; 407 | buffer[digits] = '0' + (val & 1); 408 | val >>= 1; 409 | } 410 | return buffer; 411 | } 412 | 413 | char * bin(uint16_t value, uint8_t digits) { return bin((uint32_t) value, digits); }; 414 | char * bin(uint8_t value, uint8_t digits) { return bin((uint32_t) value, digits); }; 415 | 416 | 417 | //////////////////////////////////////////////////////////// 418 | // 419 | // toRoman 420 | // 421 | // extended with 10K units generated with the same but lower case chars. 422 | // would expect a special char for 5000? 423 | // need investigation. 424 | char * toRoman(int32_t value) 425 | { 426 | char * buffer = __printbuffer; 427 | int32_t val = value; 428 | uint16_t n[13] = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 }; 429 | char roman[13][3] = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" }; 430 | 431 | buffer[0] = 0; 432 | int idx = 0; 433 | if (val == 0) 434 | { 435 | strcat(buffer, "N"); // NULL 436 | return buffer; 437 | } 438 | // handle negative values 439 | if (val < 0) 440 | { 441 | strcat(buffer, "-"); 442 | val = -val; 443 | } 444 | if (val > 100000000L) 445 | { 446 | strcat(buffer, "OVF"); // overflow 447 | return buffer; 448 | } 449 | 450 | if (val >= 10000L) 451 | { 452 | // 10K units 453 | while(val >= 10000L) 454 | { 455 | while (val >= (10000L * n[idx])) 456 | { 457 | strcat(buffer, roman[idx]); 458 | val -= (10000L * n[idx]); 459 | }; 460 | idx++; 461 | } 462 | // set chars to lower 463 | for (uint16_t i = 0; i < strlen(buffer); i++) 464 | { 465 | buffer[i] = tolower(buffer[i]); 466 | } 467 | } 468 | // reset index 469 | idx = 0; 470 | // Official part UPPER case letters 471 | while(val > 0) 472 | { 473 | while (val >= n[idx]) 474 | { 475 | strcat(buffer, roman[idx]); 476 | val -= n[idx]; 477 | }; 478 | idx++; 479 | } 480 | 481 | return buffer; 482 | } 483 | 484 | 485 | //////////////////////////////////////////////////////////// 486 | // 487 | // Distances 488 | // Experimental 489 | 490 | // step == 2,4,8,16,32,64,128,256 (default 16) 491 | char * printInch(float inch, uint16_t step) 492 | { 493 | char * buffer = __printbuffer; 494 | uint32_t whole = inch; 495 | uint8_t num = round((inch - whole) * step); 496 | if (num == step) 497 | { 498 | whole++; 499 | num = 0; 500 | } 501 | uint8_t den = step; 502 | // optional reduce 503 | while ((num > 0) && ((num & 1) == 0)) 504 | { 505 | num >>= 1; 506 | den >>= 1; 507 | } 508 | 509 | #if defined(ESP32) 510 | // ESP32 does not support %ld or ltoa() 511 | sprintf(buffer, "%d %d/%d", whole, num, den); 512 | #else 513 | sprintf(buffer, "%ld %d/%d", whole, num, den); 514 | #endif 515 | return buffer; 516 | } 517 | 518 | 519 | char * printFeet(float feet) 520 | { 521 | char * buffer = __printbuffer; 522 | uint32_t ft = feet; 523 | uint8_t inch = round((feet - ft) * 12); 524 | if (inch == 12) 525 | { 526 | ft++; 527 | inch = 0; 528 | } 529 | #if defined(ESP32) 530 | // ESP32 does not support %ld or ltoa() 531 | sprintf(buffer, "%d\"%d\'", ft, inch); 532 | #else 533 | sprintf(buffer, "%ld\"%d\'", ft, inch); 534 | #endif 535 | return buffer; 536 | } 537 | 538 | 539 | //////////////////////////////////////////////////////////// 540 | // 541 | // Comma Separated Integers 542 | // Experimental 543 | // 544 | // TODO 545 | // - merge if possible 64-32 signed-unsigned 546 | // - performance (use divmod10?) 547 | // 548 | char * csi(int64_t value) 549 | { 550 | char * buffer = __printbuffer; 551 | int index = 0; 552 | bool negative = (value < 0); 553 | if (negative) 554 | { 555 | value = -value; 556 | } 557 | int threeCount = 0; 558 | while (value > 0) 559 | { 560 | buffer[index++] = '0' + value % 10; 561 | value /= 10; 562 | threeCount++; 563 | if ((threeCount == 3) && (value > 0)) 564 | { 565 | threeCount = 0; 566 | buffer[index++] = ','; 567 | } 568 | } 569 | if (negative) 570 | { 571 | buffer[index++] = '-'; 572 | } 573 | buffer[index--] = 0; 574 | for (int i = 0, j = index; i < j; i++, j--) 575 | { 576 | char t = buffer[j]; 577 | buffer[j] = buffer[i]; 578 | buffer[i] = t; 579 | } 580 | return buffer; 581 | } 582 | 583 | char * csi(int32_t value) 584 | { 585 | char * buffer = __printbuffer; 586 | int index = 0; 587 | bool negative = (value < 0); 588 | if (negative) 589 | { 590 | value = -value; 591 | } 592 | int threeCount = 0; 593 | while (value > 0) 594 | { 595 | buffer[index++] = '0' + value % 10; 596 | value /= 10; 597 | threeCount++; 598 | if ((threeCount == 3) && (value > 0)) 599 | { 600 | threeCount = 0; 601 | buffer[index++] = ','; 602 | } 603 | } 604 | if (negative) 605 | { 606 | buffer[index++] = '-'; 607 | } 608 | buffer[index--] = 0; 609 | for (int i = 0, j = index; i < j; i++, j--) 610 | { 611 | char t = buffer[j]; 612 | buffer[j] = buffer[i]; 613 | buffer[i] = t; 614 | } 615 | return buffer; 616 | } 617 | 618 | char * csi(int16_t value) 619 | { 620 | return csi((int32_t)value); 621 | } 622 | 623 | char * csi(int8_t value) 624 | { 625 | return csi((int32_t)value); 626 | } 627 | 628 | 629 | char * csi(uint64_t value) 630 | { 631 | char * buffer = __printbuffer; 632 | int index = 0; 633 | int threeCount = 0; 634 | while (value > 0) 635 | { 636 | buffer[index++] = '0' + value % 10; 637 | value /= 10; 638 | threeCount++; 639 | if ((threeCount == 3) && (value > 0)) 640 | { 641 | threeCount = 0; 642 | buffer[index++] = ','; 643 | } 644 | } 645 | buffer[index--] = 0; 646 | for (int i = 0, j = index; i < j; i++, j--) 647 | { 648 | char t = buffer[j]; 649 | buffer[j] = buffer[i]; 650 | buffer[i] = t; 651 | } 652 | return buffer; 653 | } 654 | 655 | char * csi(uint32_t value) 656 | { 657 | char * buffer = __printbuffer; 658 | int index = 0; 659 | int threeCount = 0; 660 | while (value > 0) 661 | { 662 | buffer[index++] = '0' + value % 10; 663 | value /= 10; 664 | threeCount++; 665 | if ((threeCount == 3) && (value > 0)) 666 | { 667 | threeCount = 0; 668 | buffer[index++] = ','; 669 | } 670 | } 671 | buffer[index--] = 0; 672 | for (int i = 0, j = index; i < j; i++, j--) 673 | { 674 | char t = buffer[j]; 675 | buffer[j] = buffer[i]; 676 | buffer[i] = t; 677 | } 678 | return buffer; 679 | } 680 | 681 | char * csi(uint16_t value) 682 | { 683 | return csi((uint32_t)value); 684 | } 685 | 686 | char * csi(uint8_t value) 687 | { 688 | return csi((uint32_t)value); 689 | } 690 | 691 | 692 | //////////////////////////////////////////////////////////// 693 | // 694 | // Fraction 695 | // Experimental 696 | // Based upon Fraction library -> fractionize() 697 | // 698 | char * fraction(double value) 699 | { 700 | static char buffer[20]; 701 | if (isnan(value)) 702 | { 703 | strcpy(buffer, "nan"); 704 | return buffer; 705 | } 706 | if (isinf(value)) 707 | { 708 | if (value < 0) strcpy(buffer, "-inf"); 709 | strcpy(buffer, "inf"); 710 | return buffer; 711 | } 712 | bool negative = false; 713 | if (value < 0) 714 | { 715 | negative = true; 716 | value = -value; 717 | } 718 | 719 | float whole = 0; 720 | if (value > 1) 721 | { 722 | whole = (uint32_t)value; 723 | value -= whole; 724 | } 725 | 726 | // find nearest fraction 727 | float Precision = 0.000001; 728 | 729 | // low = (0,1), high = (1,1) 730 | int32_t lowN = 0; 731 | int32_t lowD = 1; 732 | int32_t highN = 1; 733 | int32_t highD = 1; 734 | 735 | // max 100 iterations 736 | for (int i = 0; i < 100; ++i) 737 | { 738 | float testLow = lowD * value - lowN; 739 | float testHigh = highN - highD * value; 740 | if (testHigh < Precision * highD) 741 | break; // high is answer 742 | 743 | if (testLow < Precision * lowD) 744 | { // low is answer 745 | highD = lowD; 746 | highN = lowN; 747 | break; 748 | } 749 | if (i & 1) 750 | { // odd step: add multiple of low to high 751 | float test = testHigh / testLow; 752 | int32_t count = (int32_t)test; // "N" 753 | int32_t n = (count + 1) * lowN + highN; 754 | int32_t d = (count + 1) * lowD + highD; 755 | if ((n > 0x8000) || (d > 0x10000)) // 0x8000 0x10000 756 | break; 757 | highN = n - lowN; 758 | highD = d - lowD; 759 | lowN = n; 760 | lowD = d; 761 | } 762 | else 763 | { // even step: add multiple of high to low 764 | float test = testLow / testHigh; 765 | int32_t count = (int32_t)test; // "N" 766 | int32_t n = lowN + (count + 1) * highN; 767 | int32_t d = lowD + (count + 1) * highD; 768 | if ((n > 0x10000) || (d > 0x10000)) // 0x10000 0x10000 769 | break; 770 | lowN = n - highN; 771 | lowD = d - highD; 772 | highN = n; 773 | highD = d; 774 | } 775 | } 776 | 777 | // produce the string 778 | if (whole > 0) highN += whole * highD; 779 | if (negative) 780 | { 781 | #if defined(ESP32) 782 | // ESP32 does not support %ld or ltoa() 783 | sprintf(buffer, "-%d/%d", highN, highD); 784 | #else 785 | sprintf(buffer, "-%ld/%ld", highN, highD); 786 | #endif 787 | } 788 | else 789 | { 790 | #if defined(ESP32) 791 | // ESP32 does not support %ld or ltoa() 792 | sprintf(buffer, "%d/%d", highN, highD); 793 | #else 794 | sprintf(buffer, "%ld/%ld", highN, highD); 795 | #endif 796 | } 797 | return buffer; 798 | } 799 | 800 | 801 | char * fraction(double value, uint32_t denum) 802 | { 803 | static char buffer[20]; 804 | if (isnan(value)) 805 | { 806 | strcpy(buffer, "nan"); 807 | return buffer; 808 | } 809 | if (isinf(value)) 810 | { 811 | if (value < 0) strcpy(buffer, "-inf"); 812 | strcpy(buffer, "inf"); 813 | return buffer; 814 | } 815 | bool negative = false; 816 | if (value < 0) 817 | { 818 | negative = true; 819 | value = -value; 820 | } 821 | 822 | float whole = 0; 823 | if (value > 1) 824 | { 825 | whole = (uint32_t)value; 826 | value -= whole; 827 | } 828 | 829 | uint32_t num = round(value * denum); 830 | // find GCD 831 | uint32_t a = num; 832 | uint32_t b = denum; 833 | while ( a != 0 ) 834 | { 835 | uint32_t c = a; 836 | a = b % a; 837 | b = c; 838 | } 839 | // simplify 840 | denum /= b; 841 | num /= b; 842 | 843 | // produce the string 844 | if (whole > 0) num += whole * denum; 845 | if (negative) 846 | { 847 | #if defined(ESP32) 848 | // ESP32 does not support %ld or ltoa() 849 | sprintf(buffer, "-%d/%d", num, denum); 850 | #else 851 | sprintf(buffer, "-%ld/%ld", num, denum); 852 | #endif 853 | } 854 | else 855 | { 856 | #if defined(ESP32) 857 | // ESP32 does not support %ld or ltoa() 858 | sprintf(buffer, "%d/%d", num, denum); 859 | #else 860 | sprintf(buffer, "%ld/%ld", num, denum); 861 | #endif 862 | } 863 | return buffer; 864 | } 865 | 866 | 867 | // -- END OF FILE -- 868 | 869 | 870 | 871 | -------------------------------------------------------------------------------- /printHelpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // 3 | // FILE: printHelpers.h 4 | // AUTHOR: Rob Tillaart 5 | // DATE: 2018-01-21 6 | // VERSION: 0.4.6 7 | // PURPOSE: Arduino library to help formatting for printing. 8 | // URL: https://github.com/RobTillaart/printHelpers 9 | 10 | 11 | #include "Arduino.h" 12 | #include "stdlib.h" 13 | 14 | 15 | #define PRINTHELPERS_LIB_VERSION (F("0.4.5")) 16 | // PRINTHELPERS_VERSION is obsolete in future 17 | #define PRINTHELPERS_VERSION (F("0.4.5")) 18 | 19 | 20 | // global buffer used by all functions so no static buffer in every function 21 | // is needed ==> results need to be printed/copied asap 22 | // not usable in multi-threading environments (use with care) 23 | // 24 | // 24 is a pretty safe minimum 25 | // 26 | #ifndef PRINTBUFFERSIZE 27 | #define PRINTBUFFERSIZE 66 28 | #endif 29 | 30 | 31 | 32 | //////////////////////////////////////////////////////////// 33 | // 34 | // print64() 35 | // 36 | // print64 note 37 | // buffer size 66 will work for base 2 -36 38 | // buffer size 34 will work for base 4 -36 39 | // buffer size 24 will work for base 8 -36 40 | // buffer size 22 will work for base 10 - 36 41 | 42 | char * print64(int64_t value, uint8_t base = 10); 43 | 44 | char * print64(uint64_t value, uint8_t base = 10); 45 | 46 | 47 | //////////////////////////////////////////////////////////// 48 | // 49 | // Scientific + Engineering notation 50 | // 51 | // typical buffer size for 8 byte double is 22 bytes 52 | // 15 bytes mantissa, sign dot E-xxx 53 | // em = exponentMultiple. 54 | char * scieng(double value, uint8_t decimals, uint8_t em); 55 | 56 | char * eng(double value, uint8_t decimals); // em == 3 57 | 58 | char * sci(double value, uint8_t decimals); // em == 1 59 | 60 | size_t sci(Stream &str, double value, uint8_t decimals); 61 | 62 | 63 | //////////////////////////////////////////////////////////// 64 | // 65 | // toBytes() 66 | // 67 | // official support to UDA == 1024^12 68 | // kilo mega giga tera peta exa (1024^6) 69 | // zetta yotta xona weka vunda uda (1024^12) 70 | // 71 | // (treda Byte == TDB is the next one and it is 2 char 72 | // so code wise difficult and as it is seldom used, support stops there. 73 | // 74 | // To have some support the code uses lowercase for the next 8 levels 75 | // treda sorta rinta quexa pepta ocha nena minga luma (1024 ^21 ~~ 10^63) 76 | char * toBytes(double value, uint8_t decimals = 2); 77 | 78 | 79 | //////////////////////////////////////////////////////////// 80 | // 81 | // hex() 82 | // 83 | // always leading zero's - no prefix - no separators 84 | // cast if needed. 85 | char * hex(uint64_t value, uint8_t digits = 16); 86 | char * hex(uint32_t value, uint8_t digits = 8); 87 | char * hex(uint16_t value, uint8_t digits = 4); 88 | char * hex(uint8_t value, uint8_t digits = 2); 89 | 90 | 91 | //////////////////////////////////////////////////////////// 92 | // 93 | // BIN 94 | // 95 | // always leading zero's - no prefix - no separators 96 | // cast if needed. 97 | char * bin(uint64_t value, uint8_t digits = 64); 98 | char * bin(uint32_t value, uint8_t digits = 32); 99 | char * bin(uint16_t value, uint8_t digits = 16); 100 | char * bin(uint8_t value, uint8_t digits = 8); 101 | 102 | 103 | //////////////////////////////////////////////////////////// 104 | // 105 | // toRoman() 106 | // 107 | // value should be in range 1..9999 108 | // values 10K-100M are experimental in lower case (see readme.md) 109 | char * toRoman(int32_t value); 110 | 111 | 112 | //////////////////////////////////////////////////////////// 113 | // 114 | // Distances 115 | // Experimental 116 | // 117 | // step == 2,4,8,16,32,64,128,256 (default 16) 118 | char * printInch(float inch, uint16_t step = 16); 119 | char * printFeet(float feet); 120 | 121 | 122 | //////////////////////////////////////////////////////////// 123 | // 124 | // Comma Separated Integers 125 | // Experimental 126 | // 127 | char * csi(int64_t n); 128 | char * csi(int32_t n); 129 | char * csi(int16_t n); 130 | char * csi(int8_t n); 131 | char * csi(uint64_t n); 132 | char * csi(uint32_t n); 133 | char * csi(uint16_t n); 134 | char * csi(uint8_t n); 135 | 136 | 137 | //////////////////////////////////////////////////////////// 138 | // 139 | // Fraction 140 | // Experimental 141 | // Based upon Fraction library -> fractionize() 142 | // 143 | char * fraction(double value); 144 | char * fraction(double value, uint32_t denom); 145 | 146 | 147 | // -- END OF FILE -- 148 | 149 | -------------------------------------------------------------------------------- /test/unit_test_001.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // FILE: unit_test_001.cpp 3 | // AUTHOR: Rob Tillaart 4 | // DATE: 2021-01-06 5 | // PURPOSE: unit tests for the printHelpers 6 | // https://github.com/RobTillaart/printHelpers 7 | // https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md 8 | // 9 | 10 | // supported assertions 11 | // ---------------------------- 12 | // assertEqual(expected, actual); // a == b 13 | // assertNotEqual(unwanted, actual); // a != b 14 | // assertComparativeEquivalent(expected, actual); // abs(a - b) == 0 or (!(a > b) && !(a < b)) 15 | // assertComparativeNotEquivalent(unwanted, actual); // abs(a - b) > 0 or ((a > b) || (a < b)) 16 | // assertLess(upperBound, actual); // a < b 17 | // assertMore(lowerBound, actual); // a > b 18 | // assertLessOrEqual(upperBound, actual); // a <= b 19 | // assertMoreOrEqual(lowerBound, actual); // a >= b 20 | // assertTrue(actual); 21 | // assertFalse(actual); 22 | // assertNull(actual); 23 | 24 | // // special cases for floats 25 | // assertEqualFloat(expected, actual, epsilon); // fabs(a - b) <= epsilon 26 | // assertNotEqualFloat(unwanted, actual, epsilon); // fabs(a - b) >= epsilon 27 | // assertInfinity(actual); // isinf(a) 28 | // assertNotInfinity(actual); // !isinf(a) 29 | // assertNAN(arg); // isnan(a) 30 | // assertNotNAN(arg); // !isnan(a) 31 | 32 | 33 | #include 34 | 35 | 36 | #include "Arduino.h" 37 | #include "printHelpers.h" 38 | 39 | 40 | unittest_setup() 41 | { 42 | fprintf(stderr, "PRINTHELPERS_LIB_VERSION: %s\n", (char *) PRINTHELPERS_LIB_VERSION); 43 | } 44 | 45 | 46 | unittest_teardown() 47 | { 48 | } 49 | 50 | 51 | unittest(test_constants) 52 | { 53 | assertEqual(PRINTBUFFERSIZE, 66); 54 | } 55 | 56 | 57 | unittest(test_sci) 58 | { 59 | fprintf(stderr, "%s\n", sci(PI * 1000, 6)); 60 | fprintf(stderr, "%s\n", sci(PI * 100, 6)); 61 | fprintf(stderr, "%s\n", sci(PI * 10, 6)); 62 | fprintf(stderr, "%s\n", sci(EULER * 1000, 6)); 63 | fprintf(stderr, "%s\n", sci(EULER * 100, 6)); 64 | fprintf(stderr, "%s\n", sci(EULER * 10, 6)); 65 | fprintf(stderr, "\n"); 66 | 67 | assertEqual(0, strcmp("3.141593E+01", sci(PI * 10, 6)) ); 68 | assertEqual(0, strcmp("2.718282E+01", sci(EULER * 10, 6)) ); 69 | } 70 | 71 | 72 | unittest(test_eng) 73 | { 74 | int32_t value32 = 1UL << 25; 75 | 76 | fprintf(stderr, "VALUE32 = %d\n", value32); 77 | fprintf(stderr, "%s\n", eng(PI * 1000, 6)); 78 | fprintf(stderr, "%s\n", eng(PI * 100, 6)); 79 | fprintf(stderr, "%s\n", eng(PI * 10, 6)); 80 | fprintf(stderr, "%s\n", eng(EULER * 1000, 6)); 81 | fprintf(stderr, "%s\n", eng(EULER * 100, 6)); 82 | fprintf(stderr, "%s\n", eng(EULER * 10, 6)); 83 | fprintf(stderr, "\n"); 84 | 85 | assertEqual(0, strcmp("3.141593E+03", eng(PI * 1000, 6)) ); 86 | assertEqual(0, strcmp("27.182818E+00", eng(EULER * 10, 6)) ); 87 | } 88 | 89 | 90 | unittest(test_print64) 91 | { 92 | int64_t value64 = 1ULL << 35; 93 | 94 | fprintf(stderr, "%ld\n", value64); 95 | fprintf(stderr, "%s\n", print64(value64)); 96 | fprintf(stderr, "%s\n", print64(value64, HEX)); 97 | 98 | assertEqual(0, strcmp("34359738368", print64(value64)) ); 99 | assertEqual(0, strcmp("0x800000000", print64(value64, HEX)) ); 100 | } 101 | 102 | 103 | unittest(test_toBytes) 104 | { 105 | for (int i = 0; i < 30; i++) 106 | { 107 | uint32_t t = random(pow(2, i)); 108 | fprintf(stderr, "%d\t%s\n", t, toBytes(t, 3)); 109 | } 110 | 111 | fprintf(stderr, "%.3f\n", 12345678 / 1024.0 / 1024.0); 112 | assertEqual(0, strcmp("11.773 MB", toBytes(12345678, 3)) ); 113 | } 114 | 115 | 116 | unittest(test_hex) 117 | { 118 | for (int i = 0; i < 30; i++) 119 | { 120 | uint32_t t = random(pow(2, i)); 121 | fprintf(stderr, "%d\t%s\n", t, hex(t)); 122 | } 123 | assertEqual(8, strlen(hex((uint32_t)33615)) ); 124 | assertEqual(0, strcmp("0000834F", hex((uint32_t)33615)) ); 125 | } 126 | 127 | 128 | unittest(test_bin) 129 | { 130 | for (int i = 0; i < 30; i++) 131 | { 132 | uint32_t t = random(pow(2, i)); 133 | fprintf(stderr, "%d\t%s\n", t, bin(t)); 134 | assertEqual(32, strlen(bin(t)) ); 135 | } 136 | assertEqual(32, strlen(bin((uint32_t)197493099)) ); 137 | assertEqual(0, strcmp("00001011110001011000000101101011", bin((uint32_t)197493099)) ); 138 | } 139 | 140 | 141 | unittest(test_toRoman_standard) 142 | { 143 | assertEqual(0, strcmp("I", toRoman(1)) ); 144 | assertEqual(0, strcmp("II", toRoman(2)) ); 145 | assertEqual(0, strcmp("III", toRoman(3)) ); 146 | assertEqual(0, strcmp("VIII", toRoman(8)) ); 147 | assertEqual(0, strcmp("XVIII", toRoman(18)) ); 148 | assertEqual(0, strcmp("XXVIII", toRoman(28)) ); 149 | assertEqual(0, strcmp("XXXVIII", toRoman(38)) ); 150 | assertEqual(0, strcmp("LXXXVIII", toRoman(88)) ); 151 | assertEqual(0, strcmp("CLXXXVIII", toRoman(188)) ); 152 | assertEqual(0, strcmp("CCLXXXVIII", toRoman(288)) ); 153 | assertEqual(0, strcmp("CCCLXXXVIII", toRoman(388)) ); 154 | assertEqual(0, strcmp("DCCCLXXXVIII", toRoman(888)) ); 155 | assertEqual(0, strcmp("MDCCCLXXXVIII", toRoman(1888)) ); 156 | assertEqual(0, strcmp("MMDCCCLXXXVIII", toRoman(2888)) ); 157 | assertEqual(0, strcmp("MMMDCCCLXXXVIII", toRoman(3888)) ); 158 | assertEqual(0, strcmp("MMMMDCCCLXXXVIII", toRoman(4888)) ); 159 | } 160 | 161 | 162 | unittest(test_toRoman_extended) 163 | { 164 | // zero test 165 | assertEqual(0, strcmp("N", toRoman(0)) ); 166 | // overflow 167 | assertEqual(0, strcmp("OVF", toRoman(100000001L)) ); 168 | assertEqual(0, strcmp("-OVF", toRoman(-100000001L)) ); 169 | // negative 170 | assertEqual(0, strcmp("-MCCXXXIV", toRoman(-1234))); 171 | 172 | // large 173 | assertEqual(0, strcmp("cxxiiiMMMMDLXVII", toRoman(1234567))); 174 | } 175 | 176 | 177 | unittest(test_fraction) 178 | { 179 | // positive 180 | assertEqual(0, strcmp("59/469", fraction(0.1258)) ); 181 | 182 | // zero 183 | assertEqual(0, strcmp("0/1", fraction(0)) ); 184 | 185 | // negative 186 | assertEqual(0, strcmp("-59/469", fraction(-0.1258)) ); 187 | 188 | // fixed denumerator 189 | assertEqual(0, strcmp("1/8", fraction(0.1258, 8)) ); 190 | } 191 | 192 | 193 | unittest_main() 194 | 195 | 196 | // -- END OF FILE -- 197 | --------------------------------------------------------------------------------