Добавить функцию `ldexp10()`
Функция ldexp10() должна рождать число с плавающей точкой из (целого) числа помноженного на 10 в степени экспоненты аналогично ldexp(), где в степень возводится 2.
Концептуально она должна работать так:
double ldexp10(number auto mantissa, int exponent) {
return mantissa * pow(10., exponent);
}
В общем случае неточных (inexact) вычислений должно работать корректное округление (аналогичное требованиям для from_chars()).
Есть from_chars(), которая превращает строку в число с плавающей точкой, но оно накладывает ограничение, что всё число должно быть в строке.
С этим нет проблем в тривиальных случаях типа
"1234567890.1234567890e123"
но в общем случае длина валидного числа непредсказуема, например:
"10.000000000000000000000000000000"
"1e0000000000000000000000000000001"
обе строки с валидными числами (они содержат по тридцать нулей, но в общем случае количество нулей может быть неограниченным).
Поэтому в случаях, когда распознаваемый текст приходит по кускам, например по сети, применение from_chars() становится мягко говоря затруднительным.
Мы могли бы выполнить часть работы в пользовательском коде, набрав нужное количество значащих цифр и провалидировав строку, и затем распознать мантиссу со значащими цифрами и экспоненту (например, позвав from_chars() для целых чисел или вообще делая это на лету) и позвать ldexp10().
Для примеров выше это было бы эквивалентно таким вызовам:
ldexp10(100000000000000000, -16); // 18 значащих цифр, 16 из которых после точки
ldexp10(1, 1); // 1 значащая цифра, 30 нулей и единица для экспоненты
18 десятичных значащих цифр достаточно для превращения в double.
Эквивалентно, но менее эффективно, мы могли бы переложить значащие цифры в буфер заранее известного размера (таким образом избежав выделения памяти), распознать экспоненту, поправить её с учётом расположения значащих цифр относительно точки, преваратить экспоненту в строку и положить в буфер, и превратить в число с помощью вызова from_chars():
char buffer[25] = {};
// скопировать в buffer значащие цифры (не больше 18)
// при этом запомнить откуда они приехали относительно точки
int decimalExponent = 0;
// распознать экспоненту, скорректировать с учётом расположения значащих цифр
// записать экспопненту в buffer
buffer[significantDigitsCount] = 'e';
auto e = to_chars(buffer + significantDigitsCount + 1, end(buffer), decimalExponent).ptr;
// наконец родить число со всеми гарантиями from_chars()
double d;
from_chars(buffer, e, d);
Также это было бы полезно для случаев использования нестандартных символов, для которых применение from_chars() также затруднительно, например когда для десятичной точки используется , (запятая).
Существующие реализации from_chars() в libstdc++, libc++ и стандартной библиотеке MSVC уже используют подобный код внутри, поэтому добавление ldexp10() не потребует создания абсолютно нового кода, а лишь выставит интерфейс к уже практически существующей функциональности.
Если я правильно распарсил, libstdc++ и libc++ используют вариации алгоритма Дэниела Лемира, готовую реализацию которого можно найти здесь: https://github.com/fastfloat/fast_float Релевантные места в коде: https://github.com/fastfloat/fast_float/blob/c5a3ca37c459050f367a4cb0b23c862c29242d30/include/fast_float/decimal_to_binary.h#L103 https://github.com/fastfloat/fast_float/blob/c5a3ca37c459050f367a4cb0b23c862c29242d30/include/fast_float/digit_comparison.h#L437