String to a 64 bits double.

Dear all.

I've performed a long search on the forums and on websites, and I just can't figure out.

I have a string object, containing the following value 87654321.1234. Every digit is important for my application. So I thought, --as I usually do-- : just use the 'double' type. However I can't seem to find a single function to convert a string to a double in Arduino C++(ie 64 bits, 8 bytes), and not a float (ie 32 bits, 4 bytes).

Any leads ?

And to answer the question that is gonna be asked : 'Yes I need all digits' :smiley:

Thanks in advance for any leads!

Cheers from France.

Matthias

That's because double is not implemented in the Arduino IDE.

Mattse:
And to answer the question that is gonna be asked : 'Yes I need all digits' :smiley:

Thanks in advance for any leads!

Use an Arduino DUE!

A DUE has a 32-bit microcontroller which handles real "double" (64 bits, 8 bytes) values!

If you don't mind my asking: what is the application?

You might not need to use a double.

Depending on what you're doing, it might be easier to, say, store the digits in an array, and then do arithmetic on the array elements. If you really need to save RAM, then you might use base 100 instead of base 10.

There's no double on the 8-bit AVR chips (ATmega, ATtiny) (though libraries have been made that provide a 64-bit float). The "double" is the same as a float on there.

You'll need to use a different board, use one of those libraries (ex: Arduino Playground - IEEE754tools ), or hack something lighter weight together yourself (probably depends a lot on how much manipulation you need to do on this number)

Do you have a string or do you have a String? The capitalisation is important.

If all the digits are important, then what mathematics are you doing with these exceptionally precise numbers? Unless you are trying to determine the circumference of the universe to the precision of a single atom, most calculations don't need this kind of accuracy.

If however the digits are important because they are ID numbers like student numbers, then you should not use floating-point numbers. Store the digits as a string. You don't ever perform mathematics on student numbers. What student has a number that is 1.456 times your number?

You need 40 bits to represent your example value.
I'd try int64_t

You could look at what Nick Gammon did with "big numbers" as well
http://www.gammon.com.au/forum/?id=11519

(forum screws up the link, take some extra characters off the front)

Hello to all of you.

First of all thank you very much for those answers. To answer questions:

  1. I use a String object
  2. I regret not using a Due, but I need the networking capabilities of the Yun.
  3. I need the 48 bits, since I'm encoding the frequency of an AD9852 Direct Digital Synthesizer through its SPI port. I also have some 32 bits DDS but they don't offer the spectral resolution I need.
  4. The application is for an atomic clock. The current technology at the lab is using either parallel port or series port of a computer to program the DDS. Efficient but obsolete. I'm looking to improve on that.

My salvation will come by the fact that the frequency programming is through six 8 bit registers. I simply need to encode those six values on t::he computer before transfering to the Yun. A tad less seamless, but it should work none-the-less.

Anyways; thanks for all the great answers.

Matthias

PS: I'll definitely take a look at those int64_t type thingies.

Mattse:
Hello to all of you.

First of all thank you very much for those answers. To answer questions:

  1. I use a String object

Don't.

  1. I regret not using a Due, but I need the networking capabilities of the Yun.

I don't know anything about networking, so I can't help you there.

  1. I need the 48 bits, since I'm encoding the frequency of an AD9852 Direct Digital Synthesizer through its SPI port.

How exactly does this "encoding" work? What mathematical formula does it use?
(There are ways to perform high-precision math on a device otherwise not capable of it. Think of the multiplication table you learned in school, up to 9x9, and how with pencil and paper, you can use it to multiply numbers of any size.)

I also have some 32 bits DDS but they don't offer the spectral resolution I need.

OK, so 32 bits isn't enough. Got it.

  1. The application is for an atomic clock. The current technology at the lab is using either parallel port or series port of a computer to program the DDS. Efficient but obsolete. I'm looking to improve on that.

My salvation will come by the fact that the frequency programming is through six 8 bit registers. I simply need to encode those six values on t::he computer before transfering to the Yun. A tad less seamless, but it should work none-the-less.

Again, how exactly does this "encoding" work? What kind of input, what kind of output?
If it's just a base conversion (binary to decimal or decimal to binary), that's easy enough.

Anyways; thanks for all the great answers.

I'm happy to help.

Doesn't Arduino suppport a 64-bit long long type? Or perhaps int64_t?

Regards,
Ray L.

Do you need to calculate on the Arduino - if not just pass the 48 value around as a byte array or long long int
(if its supported, cannot remember ever trying this).

Hey all.

To odometer:

  1. I know String object class pretty much sucks, but while i get my head around doing something more low-level and memory efficient, it serves its purpose darn well.

  2. The Yun part of this forum helped me with that section ^^

  3. and 4): How does encoding work ?
    Encoding is a strong word.
    For a more in-depth review of how a DDS works I'd advise you to go to
    http://www.analog.com/library/analogdialogue/archives/38-08/dds.html

For an arduino project very close to what i will do :
http://www.rocketnumbernine.com/2011/10/25/programming-the-ad9851-dds-synthesizer
He only needs 32 bits (lucky man)

Essentially it goes as follows. To output a signal at a given frequency you need 2 things. First a reference clock "f_ref' (here 300 MHz) and a tuning word "M". The principle of an n-bit DDS is this : you have a 2^n table representing a period of a sine wave, ie 2^n phases. Fundamentally, you only define the number of elements in this table that you jump every period of the reference clock. This is known as the tuning word. Its easy to see the output frequency is directly proportional to the tuning word, ie: the phase jump every time step.

For a 48 bit DDS the output frequency "f_out" is given by f_out = fref * M / (2^48). One only needs to calculate M, convert it to 6 characters (char) and program the six 8 bit registers that define the tuning word.

If it's just a base conversion (binary to decimal or decimal to binary), that's easy enough.

You seem to imply that there is a way to convert very easily a string to binary, which is pretty much what needs to be done here. Tell me how at one :smiley: !

To MarkT: the value can only be passed to the arduino as a string
To RayLivingston: Apparently yeah, but there is no "str2num" command

To Crossroads: That is actually a pretty elegant solution ! It also has a "num2str" command that could work quite decently. I'll try it out and keep you posted.

Thanks for all the great help.

Cheers!

Matthias

Mattse:
You seem to imply that there is a way to convert very easily a string to binary, which is pretty much what needs to be done here. Tell me how at one :smiley: !

If you mean a number expressed as a string (in base 10, and with a decimal point), then:

  1. There is nothing to be gained by using a String object. A char array will do well enough.

  2. The first thing to know is how many digits to expect: how many before the decimal point, and how many after. We really only need an upper limit: if there are fewer digits, that will not trouble us too much.

  3. First, let us convert the integer part of the number into binary. For each digit (character) to the left of the decimal point, you subtract '0' from it to get its numeric value. The numeric value of the whole thing is found using multiplications by 10 and additions. Just don't overflow the limit of the datatype you are using to store the result.

Example: "789" becomes (((('7'-'0')*10L) + ('8'-'0')) * 10L) + ('9'-'0')

Note: the L in 10L tells the compiler to use a long for the number (in this case, the number 10, for which an int would otherwise be used). This is important for what you're doing.

  1. After the decimal point, you are essentially trying to "scale" a value. For example, if you are trying to convert a four-place decimal number into two bytes, what you are trying to do is "stretch" the range 0 to 10000 so that it reaches from 0 to 65536. For that, of course, we multiply by 6.5536. This can be done by casting to a float, doing the multiplication, and then casting the result to an unsigned 16-bit integer. A float is good for 6 or sometimes 7 digits of precision. More than that and you need to use other tricks. Just tell me how many digits you need and I'll come up with a "trick" just for you.

Hey odometer ! and Hey crossroads.

To odometer: i need to cast a "string" (that needs a "double" to avoid bad truncation) in a "long long int" (64 bits). It's meant to be marginally truncated.

To crossroads: I've fiddled around with the library. It's actually pretty neat ! And should (modulo some ugly casting) get me out of my troubles: the principle is to use the divMod function to populate an 8-element int array. Once that's done, I can pass it as a pointer to my SPI function. and Bob's your uncle !

Thanks again !