Pages: [1] 2   Go Down
Author Topic: Serial.print() of a 64-bit DOUBLE  (Read 3482 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 92
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12428
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 smiley-wink.
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:
#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:
/*
  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:
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)
« Last Edit: January 19, 2013, 02:20:32 pm by robtillaart » Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12428
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 ...
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 92
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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.
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12428
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 smiley-wink

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)
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12428
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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]
« Last Edit: January 20, 2013, 08:29:21 am by robtillaart » Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12428
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

extra code to append to for 1.0x print.cpp
Code:
#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:
// 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
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.   smiley

extra code to append to for 1.0x print.cpp
Code:
#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:
// 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

Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12428
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

you're welcome !
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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.
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12428
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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)
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I just had a look at this code and have a few questions:

  • Why is the implementation of printLLNumber so different from the one in printNumber? If there is no particular reason to make it different, perhaps it should be more similar?
  • Did you try just modifying printNumber to accepted 64-bits numbers? Does that increase sketch sizes too much?
  • Your code includes an #ifdef, but AFAIU the compiler will automatically exclude functions that are not referenced (due to -Wl,--gc-sections and  -ffunction-sections).
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12428
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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)
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)
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.
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12428
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 )
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12428
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
In attachment at the bottom of this post

results for base 10; (times inuSec) - sketch runs base 2..16
Code:
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.

* printLong64Test.zip (2.13 KB - downloaded 18 times.)
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Pages: [1] 2   Go Up
Jump to: