Сокращение количества цифр после запятой в float на C++

Есть float, который имеет значение от 0.0 до 1.0, он приобретает значение 0.666666 Нужно сделать так чтобы после . было только 4 цифры, пробуя реализовать разные способы на VSCode, ничего не получается, что я пробовал:

  1. через деления с умножением
  2. через round и т.п.
  3. через перевод через строку
  4. через разбиение на массив чаров и перевод обратно
  5. через функцию, которая разбивает число на целое и остаток

Все попытки заканчивались тем что float вспоминал свое старое значение и возвращался в исходное состояние


Ответы (1 шт):

Автор решения: Serge3leo

В самой переменной 'float' невозможно хранить, ни 0.666666, ни 0.6667 (или 0.6666 в зависимости от того, что назвать требуемыми 4-мя цифрами). Можно хранить, только ближайшие к ним числа.

#include <cmath>
#include <iostream>
#include <limits>

using namespace std;

int main() {
    cout.precision(numeric_limits<float>::max_digits10);

    float in = 0.666666f;

    cout << "Вход Согласно IEEE: " << in << '\n';
    cout << "Предыдущее и последующее float: "
         << nextafterf(in, 0.) << ", "
         << in << ", "
         << nextafterf(in, INFINITY) << "\n\n";

    float x = round(in*10000.)/10000.;

    cout << "Выход Согласно IEEE: " << x << '\n';
    cout << "Предыдущее и последующее float: "
         << nextafterf(x, 0.) << ", "
         << x << ", "
         << nextafterf(x, INFINITY) << "\n\n";
    return 0;
}

Печатает:

$ clang++ x666.cpp && ./a.out
Вход Согласно IEEE: 0.666665971
Предыдущее и последующее float: 0.666665912, 0.666665971, 0.666666031

Выход Согласно IEEE: 0.666700006
Предыдущее и последующее float: 0.666699946, 0.666700006, 0.666700065

И действительно, 0.666700006 ближе к 0.6667, чем 0.666699946.

P.S.

Строго говоря, в операции float x = round(in*10000.)/10000. есть одна маловероятная засада, in*10000. выполняется точно, round(...)/10000. вычисляется с округлением типа double, присвоение округляет результат до float, и при крайне неудачном сочетании этих округлений, можно получить не самое ближайшее значение float, а соседнее.

Т.е. такой код не следует использовать там, где нужна гарантированная точность, к примеру, при печати многозначных чисел и т.п.

Но в данном случае, нам повезло.

P.P.S.

С точки зрения математики, для понимания вышеприведённого кода, описания стандартной функции nextafterf() достаточно, но, как советуют, невредно прочитать и человеческим языком: Число одинарной точности по IEEE, оно же, обычно, float

P.P.P.S.

Извините, исправил опечатку, код был с округлением до 4-х цифр, если нужны просто первые 4 цифры, т.е. в результате ближайшее к 0.6666, то следует использовать trunc(in*10000.)/10000..

→ Ссылка