Здравствуйте, cppguard, Вы писали:
C>Накидал тут на коленке код для вывода вещественных чисел с фиксированной запятой в привычном виде. Вышло как-то слишком просто. Имеет право на жизнь?
Если вместо велосипеда есть немного более сложная конструкция из библиотечных функций -- следует выбирать последнюю.
Он в отличие от велосипеда как правило не содержит неожиданных сюрпризов и легко узнаваема другими программистами.
C>template<typename T, unsigned N> C>class Q { C> T value; C>public: C> Q(T value): value(value) {} C> T integral() const { return value >> N; } C> T fractional() const { return value & (1 << N — 1); } C>};
Вот здесь 1 — это int, а sizeof(value) может быть меньше чем sizeof(intmax_t).
А что если N задали нулевым? Можно же!
А что если value -- знаковое. Сдвиг вправо может быть с сохранением знака.
А может быть без.
C>template<unsigned Position, unsigned Multiplier = 5> C>struct FractToString { C> static unsigned value(unsigned value, unsigned acc = 0) { C> auto d = (value >> (Position — 1) & 1) * Multiplier; C> return FractToString<Position — 1, Multiplier * 5>::value(value, acc * 10 + d); C> } C>};
Такой параметр шаблона по-умолчанию -- источник ошибок.
Опять же Position = 0 и UB.
Почему пятёрка захардкожена, что она значит?
Может быть переполнение в acc. Вообще непонятно зачем здесь какие-то рекурсивные вычисления,
по-моему всё сводится к одной линейной арифметической операции и отправке числа в ostream/snprintf/std::format.
Вообще для ввода-вывода (где перформанс не критичен) не зазорно сконвертировать в double.
Если конечно эти фиксированные числа туда влазят.
Вообще почему именно "числа с фиксированной точкой", а не рационалные дроби? Кажется не нужна эта
фиксированная точка вовсе. Проще тупо считать всегда в целых, домножив всё на некий коэффициент K
чтоб значения не утонули в шумах квантизации. А потом при выводе обратно поделить на K. В принципе
число с фиксированной точкой это оно и есть, только там K -- обязательно 2^N. Но это же совершенно
не обязательно. Хотя и удобно для быстрого деления. Но давно уже не обязательно: современные процессоры
уж точно наверняка имеют быстрый умножитель, с помощью которого деление или умножение на константу
делается быстро.