использование round
От: B0FEE664  
Дата: 11.02.18 14:10
Оценка:
Моя задача — округлить float до int.
Вопрос: можно ли для этого использовать std::round?
И если да, то как правильно избавится от предупреждения: warning C4244: '=': conversion from 'float' to 'int', possible loss of data.
И каждый день — без права на ошибку...
Re: использование round
От: rg45 СССР  
Дата: 11.02.18 14:20
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Моя задача — округлить float до int.

BFE>Вопрос: можно ли для этого использовать std::round?
BFE>И если да, то как правильно избавится от предупреждения: warning C4244: '=': conversion from 'float' to 'int', possible loss of data.

Здесь фишка в том, что у std::round тип возвращамого значения тот же, что и у параметра. Поэтому явный каст к нужному типу вполне приемлем, я считаю:

int value = int(std::round(3.14f));
--
Отредактировано 11.02.2018 14:25 rg45 . Предыдущая версия . Еще …
Отредактировано 11.02.2018 14:21 rg45 . Предыдущая версия .
Re: использование round
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 11.02.18 14:28
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Моя задача — округлить float до int.

BFE>Вопрос: можно ли для этого использовать std::round?
BFE>И если да, то как правильно избавится от предупреждения: warning C4244: '=': conversion from 'float' to 'int', possible loss of data.

я обычно так делаю:
double d = 5.5;
int i = (int)(d+0.5);


для отрицательных надо отнять, если хочешь округление к большему по модулю
Маньяк Робокряк колесит по городу
Re[2]: использование round
От: B0FEE664  
Дата: 11.02.18 14:34
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здесь фишка в том, что у std::round тип возвращамого значения тот же, что и у параметра. Поэтому явный каст к нужному типу вполне приемлем, я считаю:

R>
R>int value = int(std::round(3.14f));
R>


А гарантия того, что в value будет 3, а не 2 есть?
И каждый день — без права на ошибку...
Re[2]: использование round
От: B0FEE664  
Дата: 11.02.18 14:35
Оценка:
Здравствуйте, Marty, Вы писали:

M>я обычно так делаю:

M>
M>double d = 5.5;
M>int i = (int)(d+0.5);
M>

M>для отрицательных надо отнять, если хочешь округление к большему по модулю

Почему не используете round ?
И каждый день — без права на ошибку...
Re[3]: использование round
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 11.02.18 14:43
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Почему не используете round ?


1) Привычка — в старом стандарте его не было, да я пока не перешел на него. Домашнее попиливаю на старом, а на работе 11ый использую, но мало — там под железяки пишем, не особо тоже нужен
2) Запомнить кто что делает round, floor etc — еще в паскале не мог Но там каститься не так вроде просто, проще было таки через эти функции округлять

Кстати, тебе, чтобы самому не кастить результат, лучше использовать lround/llround — они long/long long возвращают
Маньяк Робокряк колесит по городу
Re[3]: использование round
От: rg45 СССР  
Дата: 11.02.18 14:59
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>А гарантия того, что в value будет 3, а не 2 есть?


Ну давать гарантии я бы не рискнул, но чисто эмпирически проблем никогда не возникало.

Можно попробовать в цикле прогнать через весть диапазон int.
--
Отредактировано 11.02.2018 15:03 rg45 . Предыдущая версия .
Re[4]: использование round
От: pagid Россия  
Дата: 11.02.18 18:28
Оценка:
Здравствуйте, rg45, Вы писали:

R>Можно попробовать в цикле прогнать через весть диапазон int.

Наверно хотел написать через весь диапазон float/double ?
Re[5]: использование round
От: rg45 СССР  
Дата: 11.02.18 18:35
Оценка:
Здравствуйте, pagid, Вы писали:

R>>Можно попробовать в цикле прогнать через весть диапазон int.

P>Наверно хотел написать через весь диапазон float/double ?

Мы же не ставим под сомнение правильность работы std::round? Под вопросом лишь не возникнет ли ошибки при преобразовании результата этой функции к целому числу.
--
Re[3]: использование round
От: Constructor  
Дата: 11.02.18 22:12
Оценка: +1
Здравствуйте, B0FEE664, Вы писали:

R>>Здесь фишка в том, что у std::round тип возвращамого значения тот же, что и у параметра. Поэтому явный каст к нужному типу вполне приемлем, я считаю:

R>>
R>>int value = int(std::round(3.14f));
R>>


BFE>А гарантия того, что в value будет 3, а не 2 есть?


Только для относительно небольших чисел. (1ull << std::numeric_limits<Real>::digits) + 1 — первое целое число, которое не имеет точного представления в вещественном типе Real. К этому и подобным ему числам значения вещественного типа не смогут округлиться.

Для float число значащих цифр мантиссы равно 23 + 1 = 24, поэтому пограничное "хорошее" число (которым завершается непрерывная последовательность целых чисел, представимых типом float) будет равно 16.777.216.
Для double число значащих цифр в мантиссе — 52 + 1 = 53, пограничное число — 9.007.199.254.740.992.

Проверочный код:

#include <iostream>
#include <iomanip>
#include <type_traits>
#include <limits>
#include <string>
#include <locale>


class number_punctuation_with_digit_separators final : public std::numpunct<char>
{
protected:
    virtual char do_thousands_sep() const override
    {
        return '.';
    }
    
    virtual std::string do_grouping() const override
    {
        return "\03";
    }
};


template <typename Real, typename Integer>
void print_numbers_near_real_boundary_value(
    const std::make_signed_t<Integer> limit, const std::string& real_name, const std::string& integer_name)
{
    constexpr auto real_digits = std::numeric_limits<Real>::digits;
    constexpr auto integer_digits = std::numeric_limits<Integer>::digits;
    
    static_assert(real_digits + 1 <= integer_digits, "The 'Integer' type is too short to hold the 'Real' boundary value.");
    
    const auto print_type_line = [](const auto& type_category, const auto& type_name, const auto& digits)
    {
        std::cout
            << std::left << std::setw(10) << type_category
            << std::setw(12) << type_name
            << std::right << std::setw(9) << digits << std::endl;
    };
    
    print_type_line("Type", "Type name", "Digits");
    print_type_line("Real", real_name, real_digits);
    print_type_line("Integer", integer_name, integer_digits);
    std::cout << std::endl;
    
    const auto print_number_line = [](const auto& shift, const auto& initial_integer, const auto& real,
        const auto& transformed_integer, const auto& are_equal)
    {
        std::cout
            << std::setw(5) << shift
            << std::setw(24) << initial_integer
            << std::setw(24) << real
            << std::setw(24) << transformed_integer
            << std::setw(9) << are_equal << std::endl;
    };
    
    constexpr auto boundary_value = static_cast<Integer>(1) << real_digits;
        
    print_number_line("Shift", "Initial integer", "Real", "Transformed integer", "Equal?");
    for (auto shift = - limit; shift <= limit; ++shift)
    {
        const auto initial_integer = boundary_value + shift;
        const auto real = static_cast<Real>(initial_integer);
        const auto transformed_integer = static_cast<Integer>(real);
        const auto are_equal = (initial_integer == transformed_integer) ? "yes" : "no";
        
        print_number_line(shift, initial_integer, real, transformed_integer, are_equal);
    }
    std::cout << std::endl << std::endl;
}

#define PRINT_NUMBERS_NEAR_REAL_BOUNDARY_VALUE(Real, Integer, limit) \
    print_numbers_near_real_boundary_value<Real, Integer>(limit, #Real, #Integer)

int main()
{
    std::cout.imbue(std::locale(std::locale::classic(), new number_punctuation_with_digit_separators));
    std::cout << std::fixed << std::setprecision(0);
    
    constexpr auto limit = 10;
    
    PRINT_NUMBERS_NEAR_REAL_BOUNDARY_VALUE(float, std::int32_t, limit);
    PRINT_NUMBERS_NEAR_REAL_BOUNDARY_VALUE(double, std::int64_t, limit);
}


Вывод:

Type      Type name      Digits
Real      float              24
Integer   std::int32_t       31

Shift         Initial integer                    Real     Transformed integer   Equal?
  -10              16.777.206              16.777.206              16.777.206      yes
   -9              16.777.207              16.777.207              16.777.207      yes
   -8              16.777.208              16.777.208              16.777.208      yes
   -7              16.777.209              16.777.209              16.777.209      yes
   -6              16.777.210              16.777.210              16.777.210      yes
   -5              16.777.211              16.777.211              16.777.211      yes
   -4              16.777.212              16.777.212              16.777.212      yes
   -3              16.777.213              16.777.213              16.777.213      yes
   -2              16.777.214              16.777.214              16.777.214      yes
   -1              16.777.215              16.777.215              16.777.215      yes
    0              16.777.216              16.777.216              16.777.216      yes
    1              16.777.217              16.777.216              16.777.216       no
    2              16.777.218              16.777.218              16.777.218      yes
    3              16.777.219              16.777.220              16.777.220       no
    4              16.777.220              16.777.220              16.777.220      yes
    5              16.777.221              16.777.220              16.777.220       no
    6              16.777.222              16.777.222              16.777.222      yes
    7              16.777.223              16.777.224              16.777.224       no
    8              16.777.224              16.777.224              16.777.224      yes
    9              16.777.225              16.777.224              16.777.224       no
   10              16.777.226              16.777.226              16.777.226      yes

Type      Type name      Digits
Real      double             53
Integer   std::int64_t       63

Shift         Initial integer                    Real     Transformed integer   Equal?
  -10   9.007.199.254.740.982   9.007.199.254.740.982   9.007.199.254.740.982      yes
   -9   9.007.199.254.740.983   9.007.199.254.740.983   9.007.199.254.740.983      yes
   -8   9.007.199.254.740.984   9.007.199.254.740.984   9.007.199.254.740.984      yes
   -7   9.007.199.254.740.985   9.007.199.254.740.985   9.007.199.254.740.985      yes
   -6   9.007.199.254.740.986   9.007.199.254.740.986   9.007.199.254.740.986      yes
   -5   9.007.199.254.740.987   9.007.199.254.740.987   9.007.199.254.740.987      yes
   -4   9.007.199.254.740.988   9.007.199.254.740.988   9.007.199.254.740.988      yes
   -3   9.007.199.254.740.989   9.007.199.254.740.989   9.007.199.254.740.989      yes
   -2   9.007.199.254.740.990   9.007.199.254.740.990   9.007.199.254.740.990      yes
   -1   9.007.199.254.740.991   9.007.199.254.740.991   9.007.199.254.740.991      yes
    0   9.007.199.254.740.992   9.007.199.254.740.992   9.007.199.254.740.992      yes
    1   9.007.199.254.740.993   9.007.199.254.740.992   9.007.199.254.740.992       no
    2   9.007.199.254.740.994   9.007.199.254.740.994   9.007.199.254.740.994      yes
    3   9.007.199.254.740.995   9.007.199.254.740.996   9.007.199.254.740.996       no
    4   9.007.199.254.740.996   9.007.199.254.740.996   9.007.199.254.740.996      yes
    5   9.007.199.254.740.997   9.007.199.254.740.996   9.007.199.254.740.996       no
    6   9.007.199.254.740.998   9.007.199.254.740.998   9.007.199.254.740.998      yes
    7   9.007.199.254.740.999   9.007.199.254.741.000   9.007.199.254.741.000       no
    8   9.007.199.254.741.000   9.007.199.254.741.000   9.007.199.254.741.000      yes
    9   9.007.199.254.741.001   9.007.199.254.741.000   9.007.199.254.741.000       no
   10   9.007.199.254.741.002   9.007.199.254.741.002   9.007.199.254.741.002      yes


Поэтому, если хочется абсолютно надежного округления, лучше написать обертку над std::round, которая бы проводила необходимую проверку возможности корректного округления (эту обертку можно сделать шаблонной, параметризовав целочисленным типом, к которому должно быть приведен результат выполнения std::round).
Отредактировано 11.02.2018 22:18 Constructor . Предыдущая версия .
Re[4]: использование round
От: rg45 СССР  
Дата: 11.02.18 22:55
Оценка:
Здравствуйте, Constructor, Вы писали:

R>>>Здесь фишка в том, что у std::round тип возвращамого значения тот же, что и у параметра. Поэтому явный каст к нужному типу вполне приемлем, я считаю:

R>>>
R>>>int value = int(std::round(3.14f));
R>>>


BFE>>А гарантия того, что в value будет 3, а не 2 есть?


C>Только для относительно небольших чисел. (1ull << std::numeric_limits<Real>::digits) + 1 — первое целое число, которое не имеет точного представления в вещественном типе Real. К этому и подобным ему числам значения вещественного типа не смогут округлиться.


C>Для float число значащих цифр мантиссы равно 23 + 1 = 24, поэтому пограничное "хорошее" число (которым завершается непрерывная последовательность целых чисел, представимых типом float) будет равно 16.777.216.


Эти рассуждения, конечно же верны и на их основании мы можем сделать вывод, что не всякое целое может быть представлено в виде float. Другими словами, слишком большая потеря точности может возникнуть при преобразовании int -> float. Но вопрос ведь сейчас стоит об обратном преобразовании: float -> int: может ли случиться так, что при преобразовании результа выражениия std::round(f) к целому числу, будет выбрано число, не самое близкое к результату выражения? (Где f имеет тип float и находится в диапазоне [std::numeric_limits<int>::min(), std::numeric_limits<int>::max()])
--
Отредактировано 11.02.2018 23:06 rg45 . Предыдущая версия . Еще …
Отредактировано 11.02.2018 23:01 rg45 . Предыдущая версия .
Отредактировано 11.02.2018 22:57 rg45 . Предыдущая версия .
Отредактировано 11.02.2018 22:56 rg45 . Предыдущая версия .
Re[5]: использование round
От: Constructor  
Дата: 11.02.18 23:13
Оценка:
Здравствуйте, rg45, Вы писали:

R>Эти рассуждения, конечно же верны и на их основании мы можем сделать вывод, что не всякое целое может быть представлено в виде float. Другими словами, слишком большая потеря точности может возникнуть при преобразовании int -> float.


Точно! Почему-то вдруг взбрело в голову, что intfloat как-то может повлиять на floatint.

R>Вопрос же сейчас стоит об обратном преобразовании: float -> int: может ли случиться так, что при преобразовании результа выражениия std::round(float(x)) к целому числу, будет выбрано число, не самое близкое к результату выражения?


У floatint тогда остается тогда только опасность выхода за границы представления int (std::numeric_limits<int>::min() ... std::numeric_limits<int>::max()).
Re[2]: использование round
От: T4r4sB Россия  
Дата: 11.02.18 23:15
Оценка:
Здравствуйте, Marty, Вы писали:

M>я обычно так делаю:

M>
M>double d = 5.5;
M>int i = (int)(d+0.5);
M>


И как работает это преобразование? Я вот не берусь сказать.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[3]: использование round
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 11.02.18 23:21
Оценка:
Здравствуйте, T4r4sB, Вы писали:


TB>И как работает это преобразование? Я вот не берусь сказать.


Отлично работает. А что тебя смущает?
Маньяк Робокряк колесит по городу
Re[4]: использование round
От: T4r4sB Россия  
Дата: 11.02.18 23:22
Оценка:
Здравствуйте, Marty, Вы писали:

M>Отлично работает. А что тебя смущает?


Что именно оно делает? Нужен ответ с отсылкой на доку.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[5]: использование round
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 11.02.18 23:47
Оценка:
Здравствуйте, T4r4sB, Вы писали:

M>>Отлично работает. А что тебя смущает?


TB>Что именно оно делает? Нужен ответ с отсылкой на доку.


Без ссылок не пойдет? Приведение типа double к int работает как отбрасывание дробной части. Это еще со времени чистой сишечки так работает, наверняка есть где-то в начале стандарта, там, где про фундаментальные типы пишут. 0.5 прибавляется, чтобы округление было по правилам — к ближайшему целому.

У Страуструпа в старом издании начала века в приложении B.6.2.6 о преобразовании плавающих в целые
Маньяк Робокряк колесит по городу
Re: использование round
От: uzhas Ниоткуда  
Дата: 12.02.18 09:07
Оценка: 18 (1)
Здравствуйте, B0FEE664, Вы писали:

BFE>Моя задача — округлить float до int.

BFE>Вопрос: можно ли для этого использовать std::round?
BFE>И если да, то как правильно избавится от предупреждения: warning C4244: '=': conversion from 'float' to 'int', possible loss of data.

ответ на твой вопрос: можно, предупреждение убирается с помощью явного каста (сишный или static_cast)
более подробный ответ тут: https://stackoverflow.com/questions/485525/round-for-float-in-c
в частности, попробуй lround
Re[3]: использование round
От: uzhas Ниоткуда  
Дата: 12.02.18 10:38
Оценка: 18 (3)
Здравствуйте, B0FEE664, Вы писали:

BFE>А гарантия того, что в value будет 3, а не 2 есть?


о безопасности каста к int здесь: https://stackoverflow.com/questions/47153149/is-it-safe-to-cast-to-int-from-stdround
Re[2]: использование round
От: rg45 СССР  
Дата: 12.02.18 10:54
Оценка:
Здравствуйте, uzhas, Вы писали:

U>в частности, попробуй lround


--
Re[6]: использование round
От: T4r4sB Россия  
Дата: 15.02.18 21:50
Оценка:
Здравствуйте, Marty, Вы писали:

M>Без ссылок не пойдет? Приведение типа double к int работает как отбрасывание дробной части. Это еще со времени чистой сишечки так работает, наверняка есть где-то в начале стандарта, там, где про фундаментальные типы пишут. 0.5 прибавляется, чтобы округление было по правилам — к ближайшему целому.


M>У Страуструпа в старом издании начала века в приложении B.6.2.6 о преобразовании плавающих в целые


Ну если так, то что будет для отрицательных чисел?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[7]: использование round
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 15.02.18 22:57
Оценка:
Здравствуйте, T4r4sB, Вы писали:

M>>У Страуструпа в старом издании начала века в приложении B.6.2.6 о преобразовании плавающих в целые


TB>Ну если так, то что будет для отрицательных чисел?


Будет отброшена дробная часть, не?
Маньяк Робокряк колесит по городу
Re[2]: использование round
От: VladFein США  
Дата: 16.02.18 02:01
Оценка:
Здравствуйте, rg45, Вы писали:

R>... Поэтому явный каст к нужному типу вполне приемлем, я считаю:


R>
R>int value = int(std::round(3.14f));
R>


Это разве каст?
Re[3]: использование round
От: rg45 СССР  
Дата: 16.02.18 08:48
Оценка: 12 (1)
Здравствуйте, VladFein, Вы писали:

R>>
R>>int value = int(std::round(3.14f));
R>>


VF>Это разве каст?


Конечно. Такие выражения игогда назвают "function-style conversions" и они эквивалентны "cast expressions": (int)std::round(3.14f). Вот что сказано по этому поводу в стандарте (C++17):

8.2.3 Explicit type conversion (functional notation)
2 If the initializer is a parenthesized single expression, the type conversion expression is equivalent (in definedness, and if defined in meaning) to the corresponding cast expression (8.4)...


И вот еще цитата из 8.4:

8.4 Explicit type conversion (cast notation)
2 An explicit type conversion can be expressed using functional notation (8.2.3), a type conversion operator (dynamic_cast, static_cast, reinterpret_cast, const_cast), or the cast notation.

    cast-expression:
        unary-expression
            ( type-id ) cast-expression

--
Отредактировано 16.02.2018 9:19 rg45 . Предыдущая версия . Еще …
Отредактировано 16.02.2018 9:12 rg45 . Предыдущая версия .
Re[8]: использование round
От: rg45 СССР  
Дата: 16.02.18 08:59
Оценка:
Здравствуйте, Marty, Вы писали:

M>>
M>>double d = 5.5;
M>>int i = (int)(d+0.5);
M>>


TB>>Ну если так, то что будет для отрицательных чисел?


M>Будет отброшена дробная часть, не?


Тут тебе придется с ним согласиться — твой вариант для отрицательных чисел будет работать не так как это ожидается от арифметического округления. Например, если мы захотм округлить -2.1, то получим: -2.1 -> -1.6 -> -1. Чтобы работало как надо, нужно слегка допилить:

int i = (int)(d < 0 ? d - 0.5 : d + 0.5);
--
Отредактировано 16.02.2018 8:59 rg45 . Предыдущая версия .
Re[9]: использование round
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 16.02.18 17:01
Оценка:
Здравствуйте, rg45, Вы писали:


R>Тут тебе придется с ним согласиться — твой вариант для отрицательных чисел будет работать не так как это ожидается от арифметического округления. Например, если мы захотм округлить -2.1, то получим: -2.1 -> -1.6 -> -1. Чтобы работало как надо, нужно слегка допилить:


R>
R>int i = (int)(d < 0 ? d - 0.5 : d + 0.5);
R>


Кто-то моё сообщение не дочитал

>для отрицательных надо отнять, если хочешь округление к большему по модулю
Маньяк Робокряк колесит по городу
Re[10]: использование round
От: rg45 СССР  
Дата: 16.02.18 17:03
Оценка:
Здравствуйте, Marty, Вы писали:


M>Кто-то моё сообщение не дочитал

>>для отрицательных надо отнять, если хочешь округление к большему по модулю

А да, есть такое дело. Виноват.
--
Re[8]: использование round
От: T4r4sB Россия  
Дата: 16.02.18 20:01
Оценка:
Здравствуйте, Marty, Вы писали:

M>Здравствуйте, T4r4sB, Вы писали:


M>>>У Страуструпа в старом издании начала века в приложении B.6.2.6 о преобразовании плавающих в целые


TB>>Ну если так, то что будет для отрицательных чисел?


M>Будет отброшена дробная часть, не?


Ты сначала прибавил 0.5, потом кастанул к инту, что произошло?
Подсказка: проделай это с числом -3.14
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[9]: использование round
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 16.02.18 20:40
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>>>Ну если так, то что будет для отрицательных чисел?


M>>Будет отброшена дробная часть, не?


TB>Ты сначала прибавил 0.5, потом кастанул к инту, что произошло?

TB>Подсказка: проделай это с числом -3.14

Тоже не любишь до конца дочитывать?

>для отрицательных надо отнять, если хочешь округление к большему по модулю
Маньяк Робокряк колесит по городу
Re[10]: использование round
От: T4r4sB Россия  
Дата: 16.02.18 21:10
Оценка:
Здравствуйте, Marty, Вы писали:

M>Тоже не любишь до конца дочитывать?


>>для отрицательных надо отнять, если хочешь округление к большему по модулю


Круто, теперь у тебя есть функция с хитрым ветвлением внутри.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[11]: использование round
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 16.02.18 21:12
Оценка:
Здравствуйте, T4r4sB, Вы писали:

>>>для отрицательных надо отнять, если хочешь округление к большему по модулю


TB>Круто, теперь у тебя есть функция с хитрым ветвлением внутри.


Чего тут хитрого?
Маньяк Робокряк колесит по городу
Re[12]: использование round
От: T4r4sB Россия  
Дата: 16.02.18 21:30
Оценка:
Здравствуйте, Marty, Вы писали:

M>Здравствуйте, T4r4sB, Вы писали:


>>>>для отрицательных надо отнять, если хочешь округление к большему по модулю


TB>>Круто, теперь у тебя есть функция с хитрым ветвлением внутри.


M>Чего тут хитрого?


Может, надёжнее сделать ветвление после округления?
f += 0.5f;
int i = int(f);
if (i>f) --i;

такой код правильно работает независимо от того, куда округляет каст
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[13]: использование round
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 16.02.18 21:36
Оценка:
Здравствуйте, T4r4sB, Вы писали:


TB>такой код правильно работает независимо от того, куда округляет каст


Каст не округляет, а отбрасывает дробную часть. Если бы это было не так, или на разных платформах по разному, то это была бы глобальная жопа


ЗЫ Мой код (что-то типа inproc COM) работает под Win32 x86/64, Linux x86/64/Arm, и за него я вполне спокоен. Если что-то писать для embedded, то там могут быть нюансы, но там всё надо перепроверять в любом случае. Сейчас, кстати, под STM32 говнокодю
Маньяк Робокряк колесит по городу
Re[13]: использование round
От: rg45 СССР  
Дата: 16.02.18 21:50
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Может, надёжнее сделать ветвление после округления?

TB>
TB>f += 0.5f;
TB>int i = int(f);
TB>if (i>f) --i;
TB>

TB>такой код правильно работает независимо от того, куда округляет каст

Ну где ж правильно-то? 2.9 должно округлиться до 3, у тебя получается 2. -2.1 должно округлиться до -2, у тебя получается -3.
--
Отредактировано 16.02.2018 22:15 rg45 . Предыдущая версия .
Re[14]: использование round
От: T4r4sB Россия  
Дата: 16.02.18 21:56
Оценка: 10 (1)
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, T4r4sB, Вы писали:


TB>>Может, надёжнее сделать ветвление после округления?

TB>>
TB>>f += 0.5f;
TB>>int i = int(f);
TB>>if (i>f) --i;
TB>>

TB>>такой код правильно работает независимо от того, куда округляет каст

R>Ну где ж правильно-то? 2.9 должно округлиться до 3,

Да
R>у тебя получается 2.
Неправда
R>-2.1 должно округлиться до -2,
Да
R>у тебя получается -3.
Неправда
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[15]: использование round
От: rg45 СССР  
Дата: 16.02.18 22:14
Оценка:
Здравствуйте, T4r4sB, Вы писали:

R>>Ну где ж правильно-то? 2.9 должно округлиться до 3,

TB>Да
R>>у тебя получается 2.
TB>Неправда
R>>-2.1 должно округлиться до -2,
TB>Да
R>>у тебя получается -3.
TB>Неправда

Да, все правильно, это я прогнал

Только чем это лучще? Вместо одного выражения: локальная переменная, условный оператор, модификация входного парамертра, дополнительное преобразование целого значения назад в число с плавающей точкой. В чем ты видишь выигрыш? Если это только ради того, чтоб подстраховаться на случай, если каст вдруг отработает не в ту сторону, то напрасно — как должен отработать каст прописано в стандарте языка.
--
Отредактировано 16.02.2018 22:59 rg45 . Предыдущая версия . Еще …
Отредактировано 16.02.2018 22:32 rg45 . Предыдущая версия .
Отредактировано 16.02.2018 22:21 rg45 . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.