From de6a962e427ccb47a140180361ec361223f6daee Mon Sep 17 00:00:00 2001 From: rob tillaart Date: Sun, 13 Aug 2017 17:49:07 +0200 Subject: [PATCH] Add support for 64 bit integer printing --- hardware/arduino/avr/cores/arduino/Print.cpp | 137 +++++++++++++++++-- hardware/arduino/avr/cores/arduino/Print.h | 9 +- 2 files changed, 131 insertions(+), 15 deletions(-) diff --git a/hardware/arduino/avr/cores/arduino/Print.cpp b/hardware/arduino/avr/cores/arduino/Print.cpp index 1e4c99a6552..f7ca9f5a315 100644 --- a/hardware/arduino/avr/cores/arduino/Print.cpp +++ b/hardware/arduino/avr/cores/arduino/Print.cpp @@ -1,21 +1,21 @@ /* Print.cpp - Base class that provides print() and println() Copyright (c) 2008 David A. Mellis. All right reserved. - + This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - + Modified 23 November 2006 by David A. Mellis Modified 03 August 2015 by Chuck Todd */ @@ -106,6 +106,28 @@ size_t Print::print(unsigned long n, int base) else return printNumber(n, base); } +size_t Print::print(long long n, int base) +{ + if (base == 0) { + return write(n); + } else if (base == 10) { + if (n < 0) { + int t = print('-'); + n = -n; + return printULLNumber(n, 10) + t; + } + return printULLNumber(n, 10); + } else { + return printULLNumber(n, base); + } +} + +size_t Print::print(unsigned long long n, int base) +{ + if (base == 0) return write(n); + else return printULLNumber(n, base); +} + size_t Print::print(double n, int digits) { return printFloat(n, digits); @@ -184,6 +206,20 @@ size_t Print::println(unsigned long num, int base) return n; } +size_t Print::println(long long num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(unsigned long long num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + size_t Print::println(double num, int digits) { size_t n = print(num, digits); @@ -220,15 +256,90 @@ size_t Print::printNumber(unsigned long n, uint8_t base) return write(str); } -size_t Print::printFloat(double number, uint8_t digits) -{ +// REFERENCE IMPLEMENTATION FOR ULL +// size_t Print::printULLNumber(unsigned long long n, uint8_t base) +// { + // // if limited to base 10 and 16 the bufsize can be smaller + // char buf[65]; + // char *str = &buf[64]; + + // *str = '\0'; + + // // prevent crash if called with base == 1 + // if (base < 2) base = 10; + + // do { + // unsigned long long t = n / base; + // char c = n - t * base; // faster than c = n%base; + // n = t; + // *--str = c < 10 ? c + '0' : c + 'A' - 10; + // } while(n); + + // return write(str); +// } + +// FAST IMPLEMENTATION FOR ULL +size_t Print::printULLNumber(unsigned long long n64, uint8_t base) +{ + // if limited to base 10 and 16 the bufsize can be 20 + char buf[64]; + uint8_t i = 0; + uint8_t innerLoops = 0; + + // prevent crash if called with base == 1 + if (base < 2) base = 10; + + // process chunks that fit in "16 bit math". + uint16_t top = 0xFFFF / base; + uint16_t th16 = 1; + while (th16 < top) + { + th16 *= base; + innerLoops++; + } + + while (n64 > th16) + { + // 64 bit math part + uint64_t q = n64 / th16; + uint16_t r = n64 - q*th16; + n64 = q; + + // 16 bit math loop to do remainder. (note buffer is filled reverse) + for (uint8_t j=0; j < innerLoops; j++) + { + uint16_t qq = r/base; + buf[i++] = r - qq*base; + r = qq; + } + } + + uint16_t n16 = n64; + while (n16 > 0) + { + uint16_t qq = n16/base; + buf[i++] = n16 - qq*base; + n16 = qq; + } + + size_t bytes = i; + for (; i > 0; i--) + write((char) (buf[i - 1] < 10 ? + '0' + buf[i - 1] : + 'A' + buf[i - 1] - 10)); + + return bytes; +} + +size_t Print::printFloat(double number, uint8_t digits) +{ size_t n = 0; - + if (isnan(number)) return print("nan"); if (isinf(number)) return print("inf"); if (number > 4294967040.0) return print ("ovf"); // constant determined empirically if (number <-4294967040.0) return print ("ovf"); // constant determined empirically - + // Handle negative numbers if (number < 0.0) { @@ -240,7 +351,7 @@ size_t Print::printFloat(double number, uint8_t digits) double rounding = 0.5; for (uint8_t i=0; i 0) { - n += print('.'); + n += print('.'); } // Extract digits from the remainder one at a time @@ -259,8 +370,8 @@ size_t Print::printFloat(double number, uint8_t digits) remainder *= 10.0; unsigned int toPrint = (unsigned int)(remainder); n += print(toPrint); - remainder -= toPrint; - } - + remainder -= toPrint; + } + return n; } diff --git a/hardware/arduino/avr/cores/arduino/Print.h b/hardware/arduino/avr/cores/arduino/Print.h index 058a2abbdc4..731e59f4000 100644 --- a/hardware/arduino/avr/cores/arduino/Print.h +++ b/hardware/arduino/avr/cores/arduino/Print.h @@ -39,15 +39,16 @@ class Print private: int write_error; size_t printNumber(unsigned long, uint8_t); + size_t printULLNumber(unsigned long long, uint8_t); size_t printFloat(double, uint8_t); protected: void setWriteError(int err = 1) { write_error = err; } public: Print() : write_error(0) {} - + int getWriteError() { return write_error; } void clearWriteError() { setWriteError(0); } - + virtual size_t write(uint8_t) = 0; size_t write(const char *str) { if (str == NULL) return 0; @@ -71,6 +72,8 @@ class Print size_t print(unsigned int, int = DEC); size_t print(long, int = DEC); size_t print(unsigned long, int = DEC); + size_t print(long long, int = DEC); + size_t print(unsigned long long, int = DEC); size_t print(double, int = 2); size_t print(const Printable&); @@ -83,6 +86,8 @@ class Print size_t println(unsigned int, int = DEC); size_t println(long, int = DEC); size_t println(unsigned long, int = DEC); + size_t println(long long, int = DEC); + size_t println(unsigned long long, int = DEC); size_t println(double, int = 2); size_t println(const Printable&); size_t println(void);