Pages: 1 ... 3 4 [5]   Go Down
Author Topic: faster printing of floats by divmod10() and others  (Read 11843 times)
0 Members and 1 Guest are viewing this topic.
Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 211
Posts: 13471
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

new patch ... (code increase)
Code: (patch2)
    case ENG:
    case SCI:
        n += write('E');
        if (exponent >= 0) n += write('+');
        else
        {
            exponent = -exponent;
            n += write('-');
        }
        if (exponent < 10) n += write('0');
        n += print(exponent);
        break;
Logged

Rob Tillaart

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

Rapa Nui
Offline Offline
Edison Member
*
Karma: 60
Posts: 2061
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

PS: my above replay on rounding: it shall be applicable for SCI as well I think.
So always take for the rounding "reference" the digit right to the digit which will be printed last.

0.234293
SCI,3:   2.343E-01
ENG,4: 234.3E-3
SI,4:    234.3m
« Last Edit: September 01, 2013, 04:08:28 am by pito » Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 211
Posts: 13471
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 rounding code is still based upon #decimals iso #total digits. And with the ENG notation the rounding factor depends indeed on the value of the last printed digit. But you have to determine that before printing.

Needs some thinking to make it robust for all 4 formats (first step is a notation dependent rounding and merge later)
« Last Edit: September 01, 2013, 06:09:12 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)

Rapa Nui
Offline Offline
Edison Member
*
Karma: 60
Posts: 2061
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

For "number of digits" based formats (SCI/ENG/SI) the rule is following:

The reference for rounding is the digit right to the digit to be printed last.

So when printing with 4 digits, start with 4+1= 5 digits, make rounding based on the 5th digit, and then work with the first 4 digits as usual.
« Last Edit: September 01, 2013, 04:26:20 am by pito » Logged

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

That's ok but one moment the 5th digit is O(E-1) the other time it is O(E-2) or O(E-3)

special test case is print(999.99, 4, ENG);  which becomes 1000.0E+00  (wrong) or 1.000E+03 (right)
That's why determination of the exponent should be done after rounding, but to determine the rounding factor you need to know the exponent.
« Last Edit: September 01, 2013, 06:16:01 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)

U.K
Offline Offline
Jr. Member
**
Karma: 1
Posts: 72
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

back with my changes to print.cpp to account for the actual ( real accurate digits the number can hold ) when in SCI / ENG mode, this should apply to the rounding you are seeing here ?

ie. if the data doesn't hold a value worth rounding then dont do it maybe ?
« Last Edit: September 09, 2013, 04:51:11 pm by darryl » Logged

--
 Darryl

Rapa Nui
Offline Offline
Edison Member
*
Karma: 60
Posts: 2061
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
That's ok but one moment the 5th digit is O(E-1) the other time it is O(E-2) or O(E-3)
I did not study the code, but I would expect you go from raw mantissa (significand - there are all the digits available ), for n-digits-precision take first n+1, round, go back to n and so on. You do not need exponent to know for messing with digits, I think..
Code:
For 4 digits precision:
m:  999999   exp: x
take first 4+1 digits and round
m:  99999+5   exp:x
m: 100004 and  if 1st digit went from 9->1 x=x+1
take first 4 digits
m: 1000 exp: x+1
do conversion to ENG/SI
« Last Edit: September 01, 2013, 08:22:13 am by pito » Logged

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

new BETA version of my print.cpp/.h

+ rounding SCI/ENG/SI


* Print.cpp (19.86 KB - downloaded 31 times.)
* Print.h (3.03 KB - downloaded 25 times.)
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: 211
Posts: 13471
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
That's ok but one moment the 5th digit is O(E-1) the other time it is O(E-2) or O(E-3)
I did not study the code, but I would expect you go from raw mantissa (significand - there are all the digits available ), for n-digits-precision take first n+1, round, go back to n and so on. You do not need exponent to know for messing with digits, I think..
Code:
For 4 digits precision:
m:  999999   exp: x
take first 4+1 digits and round
m:  99999+5   exp:x
m: 100004 and  if 1st digit went from 9->1 x=x+1
take first 4 digits
m: 1000 exp: x+1
do conversion to ENG/SI
- The raw mantissa is not a decimal value. It is binary, and the exponent is binary too (google IEEE754 wikipedia)
- To change the first n digits of a float into an integer value I need to multiply the float by some number. To find that number is (almost) equivalent to finding the exponent.

Quote
I did not study the code,
please do ...
Logged

Rob Tillaart

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

Peoples Republic of Cantabrigia
Offline Offline
God Member
*****
Karma: 6
Posts: 719
Arduino happiness
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Rob,

Thanks for your updates to print, I have been using bignumbers as a substitute.

Just wondering, is your fix going to become part of the default IDE?

Also, how hard would it be to implement longer 'standard' numbers in the  IDE? I am interested in int128, for example. For that matter, it would be great if double was in fact a double float...
Logged

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

Hi Rob,

Thanks for your updates to print, I have been using bignumbers as a substitute.

Just wondering, is your fix going to become part of the default IDE?

Also, how hard would it be to implement longer 'standard' numbers in the  IDE? I am interested in int128, for example. For that matter, it would be great if double was in fact a double float...
First the fixes/ideas here are not only mine as more people cooperated to get this far.

I do not expect it to become part of the default IDE soon as imho it is not tested enough yet. Furthermore there are two main features in it: faster printing and printing SCI/ENG/SI format.
- The first has currently  assembly in it, very fast but not portable to e.g. the DUE,
- The SCI/ENG/SI formatting works only for floats at the moment. Maybe 3 extra formats is too much.
- Support for printing long long; // maybe most stable part
On the positive site the lib is backwards compatible so it can be used by the ones who want to.
Finally Paul Stoffregen, Designer of the Teensy - http://www.pjrc.com/teensy/index.html -,  will incorporate the work in a coming (not perse next) release. Mentioned above somewhere.

Implementing an IEEE754(?) 64bit double in the IDE is not trivial and would take quite some time.
Implementing a proprietary larger float is simpler, one can make a class that uses for example
Code:
Class Ardouble
{

private:
  bool s;    // sign, true => negative;
  unsigned long m; // 32 bits mantisse => 9 significant digits iso 32bit float 23 bits mantissse which has 6-7 significant digits.
  int exponent; // use power of 10 => -32767 .. +32767  (OK maybe a byte is enough ;)
};

Then you need to implement a math library and conversion from and to existing base types (at least float), not very difficult but not trivial either. quite some work.
Start with +* -/% and boolean operators like < > == and !=
If that works then continue with functions like sin() cos() exp() ln() pow() sqrt() trunc() floor() ceil() etc.

Implementing an int128 class is probably easier but it will be very slow. Have you ever worked with the LONG LONG ?


 
Logged

Rob Tillaart

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

Peoples Republic of Cantabrigia
Offline Offline
God Member
*****
Karma: 6
Posts: 719
Arduino happiness
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Rob,

Yeah, I saw the assembly code and my heart sank - can't use it in the Teensy! However, I am psyched to hear that Paul may be incorporating it into the Teensy IDE... makes sense too given how many bits a 32-bit processor can handle/accumulate/etc.

As for double, I am curious why it was implemented at all if it simply defaults to float precision. I would have simply left it out.

And yes, I worked with long long until I hit a wall of sorts... one of my projects involved a least squares solver for 16 Bit ADC error minimization. Worked like a charm in Excel but numbers with 25 digits couldn't be handled by a 2^64 capable variable (i.e. can't handle anything bigger than 1.84e+19). Hence the use of the BigNumbers library (Thank you, Mr. Gammon!).

Given my knowledge re: libraries, etc. I'll simply continue using BigNumbers then for these sorts of jobs. All the more advisable since Mr. Gammon and Stoffregen have implemented BigNumbers on the Teensy as well.
Logged

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

Quote
As for double, I am curious why it was implemented at all if it simply defaults to float precision. I would have simply left it out.

I think it is mandatory to implement double to keep the compiler happy, and that the implementation is platform dependent.
Logged

Rob Tillaart

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

U.K
Offline Offline
Jr. Member
**
Karma: 1
Posts: 72
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

going on from my changes to printNumber ( in print.cpp ) where I suggested an extra parameter to being the leading zeroes ( positive for x number of them, 0 or negative to print none )

it also gains a nice addition of printing HEX and BIN numbers for free.

Code:
size_t Print::printNumber(uint32_t num, uint8_t base, uint8_t leading_zeros) {
  char buf[33]; // Assumes 8-bit chars plus zero byte. was -> "8 * sizeof(int32_t) + 1"
  char *str = &buf[sizeof(buf) - 1];
  *str = '\0';
......
  int8_t extra_digits = leading_zeros;

......
......
......

  // have we got some leading zero's to also print ?
  for ( ; extra_digits > 0; extra_digits-- ) *--str = '0';

  return write(str);
}

and then in print.h
Code:
class Print
{
private:
......
    size_t printNumber(uint32_t, uint8_t, uint8_t);

public:
......
......
    size_t print(uint8_t num, uint8_t base)     { return (base == HEX) ? printNumber(num, HEX, 2) : (base == BIN) ? printNumber(num, BIN, 8) : printNumber(num, base, NO_LEADING_ZERO); }
    size_t print(int16_t num, uint8_t base)     { return print((int32_t)num, base); }
    size_t print(uint16_t num, uint8_t base)    { return (base == HEX) ? printNumber(num, HEX, 4) : (base == BIN) ? printNumber(num, BIN, 16) : printNumber(num, base, NO_LEADING_ZERO); }
    size_t print(int32_t num, uint8_t base)     { return (base == DEC) ? print(num) : printNumber(num, base, NO_LEADING_ZERO); }
    size_t print(uint32_t num, uint8_t base)    { return (base == HEX) ? printNumber(num, HEX, 8) : (base == BIN) ? printNumber(num, BIN, 32) : printNumber(num, base, NO_LEADING_ZERO); }
......
......

lots of code missed by the "....."  but the listed codes gives the idear of what to patch / add.

Rob, your suggested way of adding the leading zeroes ( when doing the decimal part of output of course needs to be changed to the way I had used, but its useful for the freebie gain on HEX and BIN output I think.

would fix this call as well
https://github.com/arduino/Arduino/issues/1097

Logged

--
 Darryl

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

darryl, if I'm reading your code right you're changing the behaviour of Print.print(1, HEX) to output "01" instead of "1", right? I don't expect that change to be ever accepted into the Arduino codebase - doing so causes sketches that rely on the old behaviour (for example because they print the leading zero manually) to break.

To do this properly, I think the leading zero printing must be made optional, defaulting to not printing them. An easy way is to just add a "min_digits" argument to the print functions, which defaults to 0?
Logged

Pages: 1 ... 3 4 [5]   Go Up
Jump to: