Where can I find Arduino Mega dtostrf()'s implementation?

Hi

I am supper tired while writing this. I think I have found an issue with dtostrf but at this point I can not relay on my brain. I think it has problems with big numbers. But that is probably for later.

At this stage I looked for dtosrtf and I found in stdlib.h, however I cannot find the implementation file.

I am going to provide the code related to dtostrf if any of you is more familiar with the terms used in the description (ex. ingroup avr_stdlib)

/**
   \ingroup avr_stdlib
   The dtostrf() function converts the double value passed in \c val into
   an ASCII representationthat will be stored under \c s.  The caller
   is responsible for providing sufficient storage in \c s.

   Conversion is done in the format \c "[-]d.ddd".  The minimum field
   width of the output string (including the possible \c '.' and the possible
   sign for negative values) is given in \c width, and \c prec determines
   the number of digits after the decimal sign. \c width is signed value,
   negative for left adjustment.

   The dtostrf() function returns the pointer to the converted string \c s.
*/
extern char *dtostrf(double __val, signed char __width,
                     unsigned char __prec, char *__s);

/**
   \ingroup avr_stdlib
    Successful termination for exit(); evaluates to 0.
*/
#define EXIT_SUCCESS 0

/**
   \ingroup avr_stdlib
    Unsuccessful termination for exit(); evaluates to a non-zero value.
*/
#define EXIT_FAILURE 1

Maybe it only exists in the Arduino installation in a compile library object file?

@gfvalvo

Ok, I am not really sure what that means. In case that is the case, is there anyway to see the implementation?

alirezasafdari:
@gfvalvo

Ok, I am not really sure what that means. In case that is the case, is there anyway to see the implementation?

Object code is the output from the compiler and input to the linker.

When the statement

extern char *dtostrf(double __val, signed char __width, unsigned char __prec, char *__s);

is included in your code it tells the compiler: “here’s the function's prototype, don’t worry about the code that implements it, the linker will find it”

I agree with Delta_G, my money is on pilot error.

@Delta_G
This is the actual code I wrote to test. I noticed an unusual behavior in a bigger code that is why I broke it down to pieces to see what is up. I checked everything else, there are issues but I was more concerned to make sure I understand how dtostrf works. Something that I find kind of unusual (off topic) is that it does not have a way to say if it has failed. It returns a pointer to the buffer which I have not checked but cannot understand how that helps. Anyways, this a code to show why I am interested to see the implementation.

numberInput = 99999999999999999999999999999999999;
 dtostrf(numberInput, 50, 1, buf);
 Serial.write(buf, 50);
 Serial.println();

 numberInput = 999999999999999999999999999999999999;
 dtostrf(numberInput, 50, 1, buf);
 Serial.write(buf, 50);
 Serial.println();

This code produce the following result:

3136634000000000000.0
-5527149300000000000.0

Based on this
https://www.h-schmidt.net/FloatConverter/IEEE754.html
The value represented should be different unless another type of float has been use, or the dtostrf works differently on this one. I did not do a hand calculation but I did use this website as a reference to make sure there is no issue with the variable type and its limitation.

alirezasafdari:
The value represented should be different unless another type of float has been use, or the dtostrf works differently on this one. I did not do a hand calculation but I did use this website as a reference to make sure there is no issue with the variable type and its limitation.

We don't know the variable types since you didn't post complete code.

Don't post snippets; how big is buf ?

volatile float numberInput = -3, zero = 0;
char buf[50]; 

void setup()
{
	Serial.begin(115200);
	Serial.println("begin");
}

void loop()
{
	numberInput = 99999999999999999999999999999999999;
	dtostrf(numberInput, 50, 1, buf);
	Serial.write(buf, 50);
	Serial.println();

	numberInput = 999999999999999999999999999999999999;
	dtostrf(numberInput, 50, 1, buf);
	Serial.write(buf, 50);
	Serial.println();
	
	while(1);
}

Your buf is too small. No space for terminating nul character.

numberInput = 99999999999999999999999999999999999;
numberInput = 999999999999999999999999999999999999;

The two values for number input are not the same. There is one extra 9 in the second number input.

volatile float numberInput = -3, zero = 0;
char buf[50]; 

void setup()
{
  Serial.begin(115200);
  Serial.println("begin");
}

void loop()
{
  numberInput = 99999999999999999999999999999999999;
  dtostrf(numberInput, 50, 1, buf);
  Serial.write(buf, 50);
  Serial.println();

  numberInput = 99999999999999999999999999999999999;//9;
  dtostrf(numberInput, 50, 1, buf);
  Serial.write(buf, 50);
  Serial.println();
  
  while(1);
}
numberInput = 99999999999999999999999999999999999;
numberInput = 999999999999999999999999999999999999;

Those are integer constants and are too large for any supported integer type. The result is the lowest 64 bits of the value.

Append .0 the the values to make them float constants.
(Well, actually double constants... .0f for float.)

Just to help the future readers, the correct answer is given by oqibidipo. Now, I understand why they always say, we should put the '.0' at the end of the float/double value. Thank you very much oqibidipo.

The values are not the same with no doubt but the printed values were way off.

The buffer is twice larger than it should be.

As for where the implementation actually lives: It's part of avr-libc. dtostrf() is a shell that calls dtoa_prf():

http://svn.savannah.gnu.org/viewvc/avr-libc/trunk/avr-libc/libc/stdlib/dtoa_prf.c?revision=1944&view=markup

Thank you westfw for pointing out the source for implementation of dtostrf