dtostrf not acting like I'd expect

Status
Not open for further replies.

jim lee

Well-known member
I posted this on the Arduino forum, but seeing its actually a teensy I'm using. I thought I should ask here as well..

My code in code tags..

Code:
double aFloat;
char textBuff[20];

void setup() {
  Serial.begin(9600);while(!Serial);
  aFloat = 0.0000706;
  Serial.print("The float: ");Serial.println(aFloat,10);
  dtostrf(aFloat,0,0,textBuff);
  Serial.print("Result fix 0: ");Serial.println(textBuff);
  dtostrf(aFloat,0,1,textBuff);
  Serial.print("Result fix 1: ");Serial.println(textBuff);
   dtostrf(aFloat,0,1,textBuff);
  Serial.print("Result fix 2: ");Serial.println(textBuff);
}

void loop() {
  // put your main code here, to run repeatedly:

}

The output..

The float: 0.0000706000
Result fix 0: 7
Result fix 1: 0.0000
Result fix 2: 0.0000

I was expecting..
0
0.0
0.00

P.S. double or float gave the same results.

Anyone enlighten me?

Thanks.

-jim lee
 
I confirm that there is apparently a huge bug in nonstd.c since I'm seeing the same weird results. Paul???

But I found a workaround:
Code:
double aFloat;
char textBuff[20];

void setup() {
  Serial.begin(9600);while(!Serial);
  aFloat = 0.0000706;
  Serial.printf("Result fix0: %0.0f \n",aFloat);
  Serial.printf("Result fix1: %0.1f \n",aFloat);
  Serial.printf("Result fix2: %0.2f \n",aFloat);
  Serial.printf("Result fix7: %0.7f (just for control)\n",aFloat);
}

void loop() {
  // put your main code here, to run repeatedly:

}
Which gives the desired result:
Result fix0: 0
Result fix1: 0.0
Result fix2: 0.00
Result fix7: 0.0000706 (just for control)
 
And if you need to keep the formatted result in a char[] buffer, only a slight modification of your code, using the sprintf() function, works perfectly:
Code:
double aFloat;
char textBuff[20];

void setup() {
  Serial.begin(9600);while(!Serial);
  aFloat = 0.0000706;
  Serial.print("The float: ");Serial.println(aFloat,10);
  sprintf(textBuff,"%0.0f",aFloat);
  Serial.print("Result fix 0: ");Serial.println(textBuff);
  sprintf(textBuff,"%0.1f",aFloat);
  Serial.print("Result fix 1: ");Serial.println(textBuff);
  sprintf(textBuff,"%0.2f",aFloat);
  Serial.print("Result fix 2: ");Serial.println(textBuff);
}

void loop() {
  // put your main code here, to run repeatedly:

}
 
Yup, and i wouldn't use dtostrf on a teensy - it's not std-c and "printf" - formatting is much better and more compatible.
dtostrf was a "invention" of the avr-community because of the poor AVR-Chips..
 
Yup, and i wouldn't use dtostrf on a teensy - it's not std-c and "printf" - formatting is much better and more compatible.
dtostrf was a "invention" of the avr-community because of the poor AVR-Chips..

Yes! I had a look onto the dtostrf function in nonstd.c - it's ugly and slow spaghetti code...
 
Looking hardware/teensy/avr/cores/teensy3/nonstd.c, I see that dtostrf is declared:

Code:
char * dtostrf(float val, int width, unsigned int precision, char *buf)
{
  // ...
}

On ARM platforms (and any platform that cares about conforming to the standards), double and float have different sizes and representations. On AVR platforms, double and float are the same size. This means the value will be printed wrong as the dtostrf thinks it is getting a float, when it is getting a double.

As far as I can tell, the function is supposed to take a double, not a float. However, it may be a compatibility issue, in that people coming from AVR systems were using explicit float variables, and it just happened to work there. Or maybe it is a bug.
 
Ok, Well it looks like that works on Teensys. If I remember right, sprintf() with floats doesn't work on standard Arduinos.

thanks..

-jim lee
 
Yes, it is declared in nonstd.c ... But it simply does not work correctly with the ARM architecture, a byte order problem perhaps, little endian vs big endian?
 
Well.. Hmm.. I wonder if the Teensy version of dtostrf could just have sprintf() stuck inside it? This way it'd work on both platforms and no one would have to think about it again?

-jim lee
 
I wonder rather if it's really needed to continue maintaining stuff which has been tinkered to work around several flaws of outdated 8bit platforms or if it's better to make a clear cut saying that these crutches are not needed with modern Teensys and that people should better use standard C functions which are supported on all serious platforms.
 
I did some tinkering on this when there was odd behavior. It was tricky code - I got improved behavior for the user issue at the time - but just pushed the edges of the problem out a bit farther.

If only there was a Teensy Wiki where things like this could be declared - those new to Teensy could use their old way ( with the code Paul added in 2012?) find it lets them down and link to a working example for replacement.
 
Issued PULL request. GitHub was harder to navigate than editing the code was - but maybe I'm learning.

Well -that- makes me feel better at least. GitHub just baffles me to no end.

-jim lee
 
Git & GitHub sometimes baffle me too, and I use them almost every day!

If you just want to get the code, look for a green "Clone or download" button. It appears on the main page for each repository, in recent times on the right hand side (so make sure your window is wide enough, or remember to horizontal scroll if you have an unusually small screen). If you're deep linked within a repository, try to click links until you get back up to its main page. Hopefully there you'll see that green button.

When you click that green "Clone or download", ignore the clone stuff and go for the "Download ZIP" link.
 
Last edited:
I wonder rather if it's really needed to continue maintaining stuff which has been tinkered to work around several flaws of outdated 8bit platforms.

Actually, from a marketing/sales point of view I think they need to be kept running. Even If they are just name wrappers around "normal" code. Why? Because there seem to be just zillions of people using Arduinos now. This is because the are marketed to people that are NOT programmers. There is a WAY bigger pool of people that are NOT programmers than there are programmers. A non programmer will fear things like changing processors. Learning curve? Scary! Not doing that.

I got onboard with the Teensy only because :
A) I wanted to do the "eyes" thing that only runs on Teensy.
B) I could grab one from Adafruit (Always make it easy to have the customer give you his money) And..
C) I could use the Arduino IDE that I was used to, with all my code that I was used to. Learning curve hidden but look at all that RAM!!

Arduino is doing a fantastic job of herding the sheep. I don't see any sheep herding going on here. Typically engineers miss the entire lie/cheat/steal herding sheep bit. So just to keep things moving, you're going to need to siphon off the Arduino sheep to stay alive.

And that's why I think it should be fixed.

-jim lee
 
I use github mainly to "share" code between home & shop. Anything more than using it as a shared drive just gives me a headache.

-jim lee
 
I thought that quote was familiar:
... GitHub was harder to navigate than editing the code was - but maybe I'm learning.

I still can't do github right - too many months between attempts, good to see it can baffle Paul as well . . .

That dtostrf() code is no fun - who knows my prior fix may have resulted in that broken post #1 behavior - it is very fragile. I tested a series of cases but not width==0 and precision==0 - does that even make sense given the definition?

Are those major problems - that don't have a work around - at least perhaps on Teensy where maybe the code size can grow? ... I forgot how much it added ...

Below is Theremingenieur's sprint version - which of course loses sprintf when going 'smallest'::
// Sketch uses 36852 bytes (3%) of program storage space. Maximum is 1048576 bytes.
// Global variables use 5280 bytes

And the original:
//Sketch uses 30076 bytes (2%) of program storage space. Maximum is 1048576 bytes.
// Global variables use 4936 bytes
// --- and smallest - removes sprintf entirely
// Sketch uses 27568 bytes (2%) of program storage space. Maximum is 1048576 bytes.
// Global variables use 2968 bytes
 
I am in no way a github expert, but I can now navigate my way through it. How I use it depends on what it is I am wishing to do, which breaks down to 3 different ways. Note I mostly use windows so I use the github for windows app... At times I have used the github for MAC as well. As for Linux...

But in case this helps someone ... Otherwise sorry for going off topic

1) Just want to check out a library - I go up to github and use the download as zip file. You can then often use either unzip it your self or can use the Arduino Sketch->Include Library->Add zip file command to add it to Arduino...

2) I am interested in using a library and want to keep it up to date and/or know what has changed. I use the Clone or download button, choose download to desktop, which then hopefully brings up the Github for Windows and choose the location to put the library. If Arduino library I will often put it in the <arduino sketch>/libraries folder. If a Sketch, you can put anywhere. I often put it in <Arduino Sketch>/Github So I remember it is a github sketch...

From time to time, I then go to Arduino for windows and choose the project and do a Sync command, to get the latest stuff...

3) I am interested in making changes (Assumes you have an account on github). Note: If this is your own library, you do 2) Else ... Suppose I wish to make changes To Paul's version of Radiohead.
I navigate to it: https://github.com/PaulStoffregen/RadioHead

Up toward the upper right of window is a button called fork, which you push. It will replicate the library into your account. So in my case:
https://github.com/KurtE/RadioHead

Then do like 2) and download with desktop (your version). You can now start making changes to the code. However if you are planing to have others pick up changes it is often best to create a new "branch" for the changes. In github for windows, you can click on the branch button (toward the upper left), near where the current branch is listed (probably master). You click on this, it gives you an option to create a new branch based on current branch. Enter new name. In my example "SPI-Transaction-support"

You can then make all of the changes you like (preferable one fix or feature), and you can push up your changes by viewing the changes and do a Commit, which saves your changes locally into current branch. You can push these changes up to your github project by using the Sync command... Repeat as many times until you are happy.

You can then issue a Pull request back to the Original library, by using the Pull Request button toward the upper right of the window. It should say make the request against: PaulStoffregen/RadioHead master. You can update the text associated with the request... Once happy issue the request.

Hopefully it will say congratulations... and then show a Pull Request number up toward the upper right. In my case #10. You can click on this button to see the request up on github. If Paul (or whoever the library owner is) takes your PR, you will typically receive an email. Also the library owner may put up comments or the like on the PR, which again you will get email. You can also update the comments up on github... Once the changes are incorporated into the master project, you can delete your working branch and sync up to the master...

How to sync master?
a) Github for windows now has a button like: Update from PaulStroffegen/master which you can use. It will bring in all of the changes from his Master branch (fork) and apply them to your Master branch. Which you commit and sync... Will show up with some delta like "update... " Don't remember the name as I don't typically do this...

b) I use a batch script file that can be dangerous, but gets my master branch back in sync with the Pauls master. Example below for cores. Note this relies on having "upstream" setup. How to do this? https://help.github.com/articles/configuring-a-remote-for-a-fork/
My one to update the project "Cores" looks like:
Code:
cd \Users\Kurt\Documents\GitHub\Cores
git fetch upstream
git checkout master
git reset --hard upstream/master
git push origin master --force
cd %home%

Again this works for me, as I never make changes to the "master" branch, so I use the update --hard type options, which blasts away any changes in my Master branch to make mine identical in this case to Pauls master branch.

Again hope that helps.
 
Instead of swapping for sprintf() if that's too big.

just add :

val = round(val*prec)/(float)prec;

As the first line. This is the band-ade I used to get mine to work well enough to move forward. If you pre-round the number to the prec value it seems that dtostrf won't freak out. (So far..)

As for Github, its the user interface that kills me. Hittin' the green button for grabbing a new Adafruit library I got. Whenever I want to do something else, say.. look at the revision history of a source file. I'm forever looking around trying to find how to do that. I have the same trouble, although even more frustrating, trying to use blender. I just don't how they were thinking when they wrote those apps.

-jim lee
-jim lee
 
Must not have made that clear. What I meant was, hitting the green button for some code update is the limit to my comfort level.

-jim lee
 
I've put these dtostrf bugs on my todo list. At the moment (and for the last few weeks) I'm working on USB stuff which it taking all my dev time, so please don't expect me to get this patched quickly. It's definitely on the list, so I won't forget.
 
Must not have made that clear. What I meant was, hitting the green button for some code update is the limit to my comfort level
Again I am no expert. But from time to time, I have tried also tried to figure out where some changes come from. What I have found:

If you wish to know what changes happened to a specific file on github. For example suppose you wish to see what changes that happened in the Pauls cores library. For example suppose you wish to find out which changes happened with the file teensy3/HardwareSerial.h

On Github you can navigate to that file: https://github.com/PaulStoffregen/cores/blob/master/teensy3/HardwareSerial.h
in that view you will see three buttons: Raw, Blame, History.

The history button, will give you a list of all of the commits which touched that page. Clicking on blame will bring up a view which shows each line of code along with which delta that that last touched that line. I also think you can click on some of the deltas shown and maybe see when a specific line changed.
(https://help.github.com/articles/tracing-changes-in-a-file/)

on your local machine, I don't know if there is any GUI that shows you this in either github for windows or for git gui... But I know that a command line you can do things like: git blame HardwareSerial.h
 
No worries!

I'm just happy I finally got this thing working.

vacuumGauge.jpg

Sorry, I had to tell somebody!

-jim lee
 
Last edited:
Ok I tried it, it seems to work better. But I wonder what I can expect?

How many zeros can I expect to be able to type before I should expect errors?

1.000..009 <- Case 1
0.00...0009 <- Case 2

Sorry it took so long. I had to re-construct the hardware for the calculator. Then recompile and get it running with the newest changes etc.

P.S. There's something about adding volume to sound? And I see a CANBUS library? What do you have in there? Where can I find out bout some of these features. PS2 keyboard support... Looks like fun.

-jim lee
 
Last edited:
Status
Not open for further replies.
Back
Top