I'm trying to convert a string to a double, but since I'm working on a Windows native application (as in linking only to ntdll.dll), I don't have most of the standard library available. I can use basic FP support in math.h, but that's basically it.
How do I convert a string to the double closest to the rational number expressed in that string?
If you really want to get the nearest, the problem is quite hard and you need arbitrary precision arithmetic to achieve that result. See ftp://ftp.ccs.neu.edu/pub/people/will/howtoread.ps for instance.
Have you seen Open NT Native Template Library, particularly the STLx part? Basically, you get something close to normal C++ runtime in Native or Kernel code.
Assuming the JSON grammar (link currently down, Google cached version here) is acceptable to you, the following comes more or less direct from internally developed code for JSON parsing, being a literal implementation of its syntax diagram:
/*
defined functions for handling the input:
nextChar() - peeks at the next character of input
getAndRemoveCharacter() - returns the next character of input and
dequeues it
This code also assumes you have BOOL, YES and NO defined; I've left this in
for clarity
*/
double getNumber()
{
// determine whether the number is negative - it'll start with a '-' if so
BOOL negative = NO;
if(nextChar() == '-')
{
negative = YES;
getAndRemoveCharacter();
}
// seed the output number to 0
double number = 0.0;
// if the next character isn't a '0' then this is the number proper, so
// just pull off the digits and assemble the number; otherwise this number
// is either 0 itself (in which case the initial seed is correct) or a
// decimal starting in 0
if(nextChar() != '0')
{
while(nextChar() >= '0' && nextChar() <= '9')
{
number *= 10.0;
number += getAndRemoveCharacter() - '0';
}
}
else
getAndRemoveCharacter();
// if this is a decimal then jump on to the decimal part and deserialise
// digits, much as above
if(nextChar() == '.')
{
getAndRemoveCharacter();
double decimalMultiplier = 1.0;
while(nextChar() >= '0' && nextChar() <= '9')
{
decimalMultiplier /= 10.0;
number += (double)(getAndRemoveCharacter() - '0') * decimalMultiplier;
}
}
// if this number has an exponent then deal with that
if(nextChar() == 'e' || nextChar() == 'E')
{
getAndRemoveCharacter();
double exponent = 0.0;
BOOL exponentPositive = YES;
// JSON allows positive exponents to start with + (unlike
// the mantissa) and requires negative exponents to start with -
if(nextChar() == '+')
{
getAndRemoveCharacter();
}
else
if(nextChar() == '-')
{
exponentPositive = NO;
getAndRemoveCharacter();
}
// read out digits and assemble exponent
while(nextChar() >= '0' && nextChar() <= '9')
{
exponent *= 10.0;
exponent += getAndRemoveCharacter() - '0';
}
// apply exponent
number *= pow(10.0, exponentPositive ? exponent : -exponent);
}
// negate if necessary and return
return negative ? -number : number;
}
Any character type that puts the ASCII letters in the normal ASCII range will work, so it should work equally on ASCII and variants, and unicode. I guess you'd probably want to just take a string directly as an argument rather than do all those calls out; they're their in the original because the input stream is coming from afar, so they may block.
The only math.h function used in 'pow', everything else is just primitive operations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With