So do I really have to write my own parser to input these large numbers?
No, you can use
strtod().
Use example:
Code:
// src points to the number, or to whitespace preceding the number.
// It can also be a buffer. If it is n'th character in buffer, just use (buffer + n) instead.
char *src;
// end will point to the first character after the parsed number.
// We can use it to check the length and whether the parsing succeeded.
char *end;
// This is the parsed value.
double val;
// Before the conversion, we set end to a known value; the start is a good one.
end = src;
val = strtod(src, (char **)&end);
if (end == src) {
// Error: Nothing was parsed.
} else
if (!isfinite(val)) {
// Error: Infinity or not-a-number.
} else {
// Parsed (size_t)(end - src) chars.
// end points to the first unparsed character,
// which could be a letter or something.
// Parsed finite numeric value is in val.
}
All floating-point numbers are of type
m×b
x, storing the sign, exponent
x, and mantissa
m.
The floating-point types in Teensies use IEEE 754 Binary32 ('float') and Binary64 ('double'), where b is always 2, and the highest bit of mantissa is 1 unless the value is zero (all zeros).
'float'
m is 24-bit, and 'double'
m is 53-bit, thus they have 7.22 and 15.95 decimal digits worth of precision.
Because 1/10 is in binary .0
0011, i.e. 0.000110011001100110011..., they cannot represent most decimal fractions (like 0.1, 0.09, 0.007) exactly.
Fractions like 1/2 = 0.5, 1/4 = 0.25, and those that can be expressed as a sum of 1/2
k (where minimum and maximum
k differ by not more than 23 or 52, for 'float' and 'double' respectively), are the only ones that can be represented exactly. For example, 0.75 is equal to 0.11
2 in binary. (The
2 is the traditional 'math' way to indicate the number is in binary, AKA base-2.)
If you need even more precision, fixed-point formats are much easier to implement than floating-point.
Then, the question is whether you do more computation or input/output with them. In particular, on Teensies, the limbs can be 32-bit, 28-bit (for more efficient conversion to/from decimal formats for 14% larger storage), nine-digit decimal (000000000..999999999) in 30-bit unsigned integer, or one of the other binary-coded decimal formats. The 32-bit one is most efficient for computation, generally speaking. The 28-bit halves the number of multiplications during conversions, but since Teensies tend to have fast (single-cycle or close) multiplication operations, it is probably not worthwhile. The nine-digit decimal is precise (all decimal fractions can be expressed exactly) and extremely fast for decimal input and output, as well as addition and subtraction, but multiplication and division is slowed down due to an extra division-modulus per limb. All trigonometric functions need to be expressed in series form, and are thus quite slow, although there are some tricks to speed up the calculation (notably using double-precision approximate and then iterative optimization using e.g. Newton-Raphson).
Knowing what kind of math operations you need to do with these would help.
When using floating-point types, precision-preserving approaches to seemingly trivial things, like summing a set of values, helps a lot: see
Kahan summation algorithm. There are many other approaches for various operations, including alternatives for summing (especially if the values are already sorted).