Arduino Forum

Products => Arduino Due => Topic started by: BKnight760 on Jan 19, 2013, 06:34 am

Title: Serial.print() of a 64-bit DOUBLE
Post by: BKnight760 on Jan 19, 2013, 06:34 am
I've read in the Reference section that the DOUBLE data type on the Due is a 64-bit variable.  Unfortunately, the Serial.print won't handle a 64-bit variable.  I haven't been able to print out a uint64_t either.

Any ideas of how to print this?

I've looked into bit shifting the top 32-bits into an unsigned int, and then printing the high 32-bits followed by the low 32-bits, but apparently the bit shift operator defaults to a 32-bit operation as well.

The reason I'm trying to do this is because I stuck a 16 GB SD card into my wifi shield and can read it using the SD library, but it won't show the correct size of the SD card because it's so large.  The unsigned int will only show up to ~4 GB.  (0xFFFFFFFF = 4294967295 decimal).

Time to program the BigInt class?
Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: robtillaart on Jan 19, 2013, 08:01 pm
Made this code for printing int64_t and uint64_t some time ago on an UNO - IDE 0.22;  

Should work for DUE too I guess, but is not tested other than on my UNO (so all disclaimers apply ;).
Just received my first DUE yesterday not downloaded the IDE for that to play with it.

Add this snippet to print.cpp to print the 64 bit integers, mind you! a simple sketch adds about 8KB!

Snippet for print.cpp
Code: [Select]

#ifdef SUPPORT_LONGLONG

void Print::println(int64_t n, uint8_t base)
{
 print(n, base);
 println();
}

void Print::print(int64_t n, uint8_t base)
{
 if (n < 0)
 {
   print((char)'-');
   n = -n;
 }
 if (base < 2) base = 2;
 print((uint64_t)n, base);
}

void Print::println(uint64_t n, uint8_t base)
{
 print(n, base);
 println();
}

void Print::print(uint64_t n, uint8_t base)
{
 if (base < 2) base = 2;
 printLLNumber(n, base);
}

void Print::printLLNumber(uint64_t n, uint8_t base)
{
 unsigned char buf[16 * sizeof(long)];
 unsigned int i = 0;

 if (n == 0)
 {
   print((char)'0');
   return;
 }

 while (n > 0)
 {
   buf[i++] = n % base;
   n /= base;
 }

 for (; i > 0; i--)
   print((char) (buf[i - 1] < 10 ?
     '0' + buf[i - 1] :
     'A' + buf[i - 1] - 10));
}
#endif


patched version of print.h
Code: [Select]

/*
 Print.h - 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
*/

#ifndef Print_h
#define Print_h

#include <inttypes.h>
#include <stdio.h> // for size_t

#include "WString.h"

#define DEC 10
#define HEX 16
#define OCT 8
#define BIN 2
#define BYTE 0

// uncomment next line to support printing of 64 bit ints.
#define SUPPORT_LONGLONG

class Print
{
 private:
   void printNumber(unsigned long, uint8_t);
#ifdef SUPPORT_LONGLONG
void printLLNumber(uint64_t, uint8_t );
#endif
   void printFloat(double, uint8_t);
 public:
   virtual void write(uint8_t) = 0;
   virtual void write(const char *str);
   virtual void write(const uint8_t *buffer, size_t size);
   
   void print(const String &);
   void print(const char[]);
   void print(char, uint8_t = BYTE);
   void print(unsigned char, uint8_t = BYTE);
   void print(int, uint8_t = DEC);
   void print(unsigned int, uint8_t = DEC);
   void print(long, uint8_t = DEC);
   void print(unsigned long, uint8_t = DEC);
   void print(double, uint8_t = 2);

   void println(const String &s);
   void println(const char[]);
   void println(char, uint8_t = BYTE);
   void println(unsigned char, uint8_t = BYTE);
   void println(int, uint8_t = DEC);
   void println(unsigned int, uint8_t = DEC);
   void println(long, uint8_t = DEC);
   void println(unsigned long, uint8_t = DEC);
   void println(double, uint8_t = 2);
   void println(void);

#ifdef SUPPORT_LONGLONG
void println(int64_t, uint8_t = DEC);
void print(int64_t, uint8_t = DEC);
void println(uint64_t, uint8_t = DEC);
void print(uint64_t, uint8_t = DEC);
#endif

};

#endif



Can you confirm this works on DUE?
Code: [Select]
void setup()
{
 Serial.begin(9600);
 Serial.print(1000000000000LL, 10);
 Serial.println();
 Serial.print(-1000000000000LL, 10);
 Serial.println();
 Serial.println(1000000000000LL, 10);
 Serial.println(-1000000000000LL, 10);
}

void loop(){}


printing doubles I did not investigate yet but can be tackled in the same way as printing floats are handled using the printing of longs (on UNO)
Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: robtillaart on Jan 19, 2013, 09:05 pm
Just had a look at the 1.0 IDE version, (still not downloaded DUE IDE )

The code should be extended with size_t return values, and some math to calc the right value ...
Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: BKnight760 on Jan 19, 2013, 10:23 pm
I made those modifications to print.cpp and print.h, and it worked just great on my DUE.  I am now able to display the true size of my 16 GB SD Card:

Code: [Select]
Volume size (bytes): 15923150848

I didn't change the methods to size_t though, it worked fine without that change.  (I did try it, and it threw a bunch of errors, so I left them as void).

As you noted, the change does add about 8KB, but heck, I've got a DUE with 512K program memory, so I can spare the extra 8K.  Woot.
Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: robtillaart on Jan 19, 2013, 10:43 pm
good to hear it works!

Is the performance fast enough?
can you test printing 100 int64's @115200 and time it with micros?
and do the same with 100 int32's?

The size_t thing should be solved someday but apparently not now ;)

You also stated that you were not able to print a double ? but floats works?
(there is definitely no x.yyyE-nnn engineering format yet)
Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: robtillaart on Jan 20, 2013, 12:50 pm
Did some rework on the printing of int64's.
Most important, I replaced the % math with less expensive code => test app size went from 9766 => 6966
+ added constrain for base
+ merged the printLLnumber into print(uint64_t, int); as that was the only one that called.

still todo
- need to support base = BYTE. not supported in 1.0 so will not be implemented. (patched below)
- include size_t  for 1.0 version

Code: [Select]

#ifdef SUPPORT_LONGLONG

void Print::println(int64_t number, uint8_t base)
{
 print(number, base);
 println();
}

void Print::print(int64_t number, uint8_t base)
{
 if (number < 0)
 {
   write('-');
   number = -number;
 }
 print((uint64_t)number, base);
}

void Print::println(uint64_t number, uint8_t base)
{
 print(number, base);
 println();
}

void Print::print(uint64_t number, uint8_t base)
{
 unsigned char buf[64];
 uint8_t i = 0;

 if (number == 0)
 {
   print((char)'0');
   return;
 }
 
 if (base < 2) base = 2;
 else if (base > 16) base = 16;

 while (number > 0)
 {
   uint64_t q = number/base;
   buf[i++] = number - q*base;
   number = q;
 }
 for (; i > 0; i--)
   write((char) (buf[i - 1] < 10 ?
     '0' + buf[i - 1] :
     'A' + buf[i - 1] - 10));
}
#endif


update ==> remove printLLnumber() from print.h too

update ==> I had already patched print.cpp  to use uint8_t for param base in all functions. [change to int will solve this]
Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: robtillaart on Jan 20, 2013, 02:37 pm
extra code to append to for 1.0x print.cpp
Code: [Select]

#ifdef SUPPORT_LONGLONG

size_t Print::println(int64_t number, int base)
{
 size_t n = 0;
 n += print(number, base);
 n += println();
 return n;
}

size_t Print::print(int64_t number, int base)
{
 size_t n = 0;
 if (number < 0)
 {
   write('-');
number = -number;
n++;
 }
 n += print((uint64_t)number, base);
 return n;
}

size_t Print::println(uint64_t number, int base)
{
 size_t n = 0;
 n += print((uint64_t)number, base);
 n += println();
 return n;
}

size_t Print::print(uint64_t number, int base)
{
 size_t n = 0;
 unsigned char buf[64];
 uint8_t i = 0;

 if (number == 0)
 {
   n += print((char)'0');
   return n;
 }
 
 if (base < 2) base = 2;
 else if (base > 16) base = 16;

 while (number > 0)
 {
   uint64_t q = number/base;
   buf[i++] = number - q*base;
   number = q;
 }
 
 for (; i > 0; i--)
   n += write((char) (buf[i - 1] < 10 ?
     '0' + buf[i - 1] :
     'A' + buf[i - 1] - 10));
 
  return n;
}
#endif


additional code for 1.0x print.h
Code: [Select]

// uncomment next line for int64 support
#define SUPPORT_LONGLONG

....

#ifdef SUPPORT_LONGLONG
size_t println(int64_t, int = DEC);
size_t print(int64_t, int = DEC);
size_t println(uint64_t, int = DEC);
size_t print(uint64_t, int = DEC);
#endif

Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: platezero on Apr 29, 2013, 05:07 pm
robtillaart, thanks for your great code

i test with uint64_t a = 4294329243;

it's can display in DEC, BIN, OCT, HEX all correct.

thank you very much.   :)


extra code to append to for 1.0x print.cpp
Code: [Select]

#ifdef SUPPORT_LONGLONG

size_t Print::println(int64_t number, int base)
{
 size_t n = 0;
 n += print(number, base);
 n += println();
 return n;
}

size_t Print::print(int64_t number, int base)
{
 size_t n = 0;
 if (number < 0)
 {
   write('-');
number = -number;
n++;
 }
 n += print((uint64_t)number, base);
 return n;
}

size_t Print::println(uint64_t number, int base)
{
 size_t n = 0;
 n += print((uint64_t)number, base);
 n += println();
 return n;
}

size_t Print::print(uint64_t number, int base)
{
 size_t n = 0;
 unsigned char buf[64];
 uint8_t i = 0;

 if (number == 0)
 {
   n += print((char)'0');
   return n;
 }
 
 if (base < 2) base = 2;
 else if (base > 16) base = 16;

 while (number > 0)
 {
   uint64_t q = number/base;
   buf[i++] = number - q*base;
   number = q;
 }
 
 for (; i > 0; i--)
   n += write((char) (buf[i - 1] < 10 ?
     '0' + buf[i - 1] :
     'A' + buf[i - 1] - 10));
 
  return n;
}
#endif


additional code for 1.0x print.h
Code: [Select]

// uncomment next line for int64 support
#define SUPPORT_LONGLONG

....

#ifdef SUPPORT_LONGLONG
size_t println(int64_t, int = DEC);
size_t print(int64_t, int = DEC);
size_t println(uint64_t, int = DEC);
size_t print(uint64_t, int = DEC);
#endif


Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: robtillaart on Apr 29, 2013, 06:19 pm
you're welcome !
Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: lordofentropy on Jun 06, 2013, 02:44 pm
After following this thread I tried to implement it using Arduino IDE 1.0.x with the arduino mega and I receive these compiling errors
Code: [Select]

C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp: In member function 'size_t Print::print(const __FlashStringHelper*)':
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:45: warning: '__progmem__' attribute ignored
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp: At global scope:
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:274: error: prototype for 'size_t Print::println(int64_t, int)' does not match any in class 'Print'
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\/Print.h:89: error: candidates are: size_t Print::println(uint64_t, uint8_t)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\/Print.h:87: error:                 size_t Print::println(int64_t, uint8_t)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:128: error:                 size_t Print::println()
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:198: error:                 size_t Print::println(const Printable&)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:191: error:                 size_t Print::println(double, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:184: error:                 size_t Print::println(long unsigned int, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:177: error:                 size_t Print::println(long int, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:170: error:                 size_t Print::println(unsigned int, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:163: error:                 size_t Print::println(int, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:156: error:                 size_t Print::println(unsigned char, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:149: error:                 size_t Print::println(char)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:142: error:                 size_t Print::println(const char*)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:135: error:                 size_t Print::println(const String&)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:116: error:                 size_t Print::println(const __FlashStringHelper*)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:282: error: prototype for 'size_t Print::print(int64_t, int)' does not match any in class 'Print'
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\/Print.h:90: error: candidates are: size_t Print::print(uint64_t, uint8_t)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\/Print.h:88: error:                 size_t Print::print(int64_t, uint8_t)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:123: error:                 size_t Print::print(const Printable&)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:111: error:                 size_t Print::print(double, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:105: error:                 size_t Print::print(long unsigned int, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:89: error:                 size_t Print::print(long int, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:84: error:                 size_t Print::print(unsigned int, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:79: error:                 size_t Print::print(int, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:74: error:                 size_t Print::print(unsigned char, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:69: error:                 size_t Print::print(char)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:64: error:                 size_t Print::print(const char*)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:55: error:                 size_t Print::print(const String&)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:43: error:                 size_t Print::print(const __FlashStringHelper*)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:295: error: prototype for 'size_t Print::println(uint64_t, int)' does not match any in class 'Print'
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\/Print.h:89: error: candidates are: size_t Print::println(uint64_t, uint8_t)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\/Print.h:87: error:                 size_t Print::println(int64_t, uint8_t)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:128: error:                 size_t Print::println()
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:198: error:                 size_t Print::println(const Printable&)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:191: error:                 size_t Print::println(double, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:184: error:                 size_t Print::println(long unsigned int, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:177: error:                 size_t Print::println(long int, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:170: error:                 size_t Print::println(unsigned int, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:163: error:                 size_t Print::println(int, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:156: error:                 size_t Print::println(unsigned char, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:149: error:                 size_t Print::println(char)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:142: error:                 size_t Print::println(const char*)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:135: error:                 size_t Print::println(const String&)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:116: error:                 size_t Print::println(const __FlashStringHelper*)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:303: error: prototype for 'size_t Print::print(uint64_t, int)' does not match any in class 'Print'
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\/Print.h:90: error: candidates are: size_t Print::print(uint64_t, uint8_t)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\/Print.h:88: error:                 size_t Print::print(int64_t, uint8_t)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:123: error:                 size_t Print::print(const Printable&)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:111: error:                 size_t Print::print(double, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:105: error:                 size_t Print::print(long unsigned int, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:89: error:                 size_t Print::print(long int, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:84: error:                 size_t Print::print(unsigned int, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:79: error:                 size_t Print::print(int, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:74: error:                 size_t Print::print(unsigned char, int)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:69: error:                 size_t Print::print(char)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:64: error:                 size_t Print::print(const char*)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:55: error:                 size_t Print::print(const String&)
C:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\Print.cpp:43: error:                 size_t Print::print(const __FlashStringHelper*)


Does anyone have any suggestions? Thanks.
Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: robtillaart on Jun 06, 2013, 07:26 pm
It worked on 1.0.4  (I do not run 1.0.5)   

Can you post your edited print.h and print.cpp file (please use code tags)
Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: matthijskooijman on Dec 24, 2013, 02:17 pm
I just had a look at this code and have a few questions:

Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: robtillaart on Dec 24, 2013, 11:27 pm
in #7 printLLnumber is replaced by a print that is more similar to existing code.

What I still am thinking about with this one is that the 64 bit division is REALLY expensive..

First strategy is to scale down asap
Code: (experimental) [Select]

size_t Print::print(uint64_t number64, uint8_t base)  // base to uint8_t
{
  size_t n = 0;
  unsigned char buf[64];
  uint8_t i = 0;

  if (number64 == 0)
  {
    write('0');  // write is faster than print.
    return  1;
  }
 
  // keep base in "reasonable limits
  if (base < 2) base = 2;
  else if (base > 16) base = 16;

  // use 64 bit math asl long as needed
  while (number64 >  4294967295)  // > 32 bit
  {
    uint64_t q = number64/base;
    buf[i++] = number64 - q*base;
    number64 = q;
  }

uint32_t number32 = number64;
while (number32  >  65535)  // > 16 bit but fit in 32 bit
  {
    uint32_T q = number32/base;
    buf[i++] = number32 - q*base;
    number32 = q;
  }

// maybe this step is too much?
uint16_t number16 = number32;  // last digits fit in 16 bit
while (number16 >  0)
  {
    uint16_T q = number16/base;
    buf[i++] = number16 - q*base;
    number16 = q;
  }
 
  n += i;
  for (; i > 0; i--)
    write((char) (buf[i - 1] < 10 ?
      '0' + buf[i - 1] :
      'A' + buf[i - 1] - 10));
 
   return n;
}


Another strategy is to split of 4 digits at a time and use a print (16 bit)
has smaller footprint but also a "problem"...
Code: (experimental) [Select]

size_t Print::print(uint64_t number64, uint8_t base)  // base to uint8_t
{
  if (number64 == 0)
  {
    write('0');  // write is faster than print.
    return  1;
  }
 
  // keep base in "reasonable limits
  if (base < 2) base = 2;
  else if (base > 16) base = 16;

  size_t n = 0;
  while (number64 >  0)
  {
    uint64_t  q = number64 / 1000;  // 7 divisions max,
    uint16_t r =  number64 - q * 1000;

    n += print(r, base);  //  <<<<<<<<  problem here is leading zeroos.

    number64 = q;
  }
   return n;
}


The two strategies can be "mixed" to maximize performance,
split the 64 bit in
- one 16 bit  4 digits max:  9,999
- two 32 bits numbers of 9 digits max: 999,999,999
and split the 32 bit numbers in three (max) 4 digit 16 bit numbers
The 16 bit math that remains is faster that a 64 bit %/ 10 loop.

Not tested well what best strategy is, but there is def. room for further improvements.
Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: robtillaart on Dec 25, 2013, 07:20 am
The internal buffer [64] is way too large if base = 10; ,
264-1 = 18,446,744,073,709,551,615 => 20 digits
so buffer[24] should be enough, if only base 10 and base 16 are used.

(in fact in base 10 an N bit number will fit always in a string of length  N/3 + 3 )
Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: robtillaart on Dec 25, 2013, 01:27 pm
Some variations of printing uint64_t  tested this morning.

Measurements:
- NOT embedded in the print Class => sort of simulation more.
- one call only  with MAX U LONG LONG
- measurement in micros (stepsize 4), but the results are not that close.
- nothing done to prevent interrupt, so indicative at best.

Code: [Select]

In attachment at the bottom of this post


results for base 10; (times inuSec) - sketch runs base 2..16
Code: [Select]

10

18446744073709551615 printLLNumber 13012 first version for reference only
18446744073709551615 print0 7620
18446744073709551615 print1 7632
18446744073709551615 print2 5004
6155517097374444618 print3 4064 <<< FAIL, but was interesting wrt thinking how to
18446744073709551615 print4 5136
18446744073709551615 print5 5128
18446744073709551615 print6 2052 <<< base 10 only
18446744073709551615 print7 1812 <<< base 10 only
18446744073709551615 print8 1888
18446744073709551615 print9 2160
18446744073709551615 print10 1836

in general, again a trade of size versus speed.
Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: robtillaart on Dec 25, 2013, 01:47 pm
From the test above some preliminary  conclusions:

printing 64 bits integers is not a daily job on an Arduino. 64 bit math is slow, but as these implementations show there is quite some performance to be gained at the cost of some footprint.

print6() is dedicated for base10 only, it has very good performance footprint ratio.

print9() is my favorite for all bases. The implementation is still reasonably straightforward while performance is very good. The footprint is substantially larger than print6()  (estimate factor 2+)
Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: MarkT on Dec 26, 2013, 12:37 pm
Quote

printing 64 bits integers is not a daily job on an Arduino. 64 bit math is slow, but as these implementations show there is quite some performance to be gained at the cost of some footprint.


Well on the Due there is 512kB of program memory and its 32 bit throughout.  The
only performance "gotcha" is the lack of divide hardware.  Any method of printing that
avoids / and % will likely win.  The fastest base 10 printing algorithm is test-subtraction
using a table of powers of ten - with that much flash available its not prohibitive to
store the table.

You need to avoid Serial library calls to get a true benchmark figure, in other
words time sprintf style conervsion, not printf style.
Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: sadr0b0t on Aug 08, 2017, 06:11 pm
Has this code ever been added to mainstream? I am on IDE 1.6.9 and Serial.println with "long long" is not going to compile.
Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: robtillaart on Aug 13, 2017, 09:14 pm
@sadr0b0t

Created a pull request - https://github.com/arduino/Arduino/pull/6608 - with the code for long long ...


Title: Re: Serial.print() of a 64-bit DOUBLE
Post by: ard_newbie on Aug 14, 2017, 09:24 am
You can print uin64_t, int64_t and double this way:

Code: [Select]

uint64_t bignum0 = 0xFFFFFFFFFFFFFFllu;
uint64_t bignum1 = pow(2, 64) - 1;
int64_t bignum2 = - pow(2, 62);
double bignum3 = -1.123456789876543;

void setup() {
  Serial.begin(250000);
}

void loop() {
  printf(" bignum0 = 0x%llx\n", bignum0);
  printf(" bignum1 = %llu\n", bignum1);
  printf(" bignum2 = %lld\n", bignum2);
  Serial.print(" bignum3 = ");
  Serial.println(bignum3,15);
  delay(1000);
}