LINUX.ORG.RU

[C/C++] double -> int


0

1

(int)std::numeric_limits<double>::infinity() даёт не бесконечность, а INT_MIN.

Как сконвертировать double в int так, чтобы значения обрезались по [INT_MIN; INT_MAX] и с нормальной обработкой inf?

upd: бесконечности для int нету, так что надо тупо обрезать по [INT_MIN; INT_MAX]

★★★★★

Последнее исправление: Obey-Kun (всего исправлений: 2)

проще всего руками или ковырять x86 спец инструкции если нужна производительность

bga_ ★★★★
()
Ответ на: комментарий от Tanger

И как это в одну строчку сделать? У меня побольше строчек получилось (не проверял, набрал в окошке браузера).

template <class T1, T2>
T2 convert(T1 a) {
    if (a == std::numeric_limits<T2>::infinity()) {
        return std::numeric_limits<T1>::infinity();
    }
    if (a == -std::numeric_limits<T2>::infinity()) {
        return -std::numeric_limits<T1>::infinity();
    }

    T2 min = std::numeric_limits<T1>::min();
    T2 max = std::numeric_limits<T1>::max();

    if (a < min) {
        a = min;
    } else if (a > max) {
        a = max;
    }
    return a;
}

Obey-Kun ★★★★★
() автор топика

В Boost что-то такое есть.

#include <cassert>
#include <boost/numeric/conversion/converter.hpp>

int main() {

    typedef boost::numeric::converter<int,double> Double2Int ;

    int x = Double2Int::convert(2.0);
    assert ( x == 2 );

    int y = Double2Int()(3.14); // As a function object.
    assert ( y == 3 ) ; // The default rounding is trunc.

    try
    {
        double m = boost::numeric::bounds<double>::highest();
        int z = Double2Int::convert(m); // By default throws positive_overflow()
    }
    catch ( boost::numeric::positive_overflow const& )
    {
    }

    return 0;
}

Только, как я понял, оно не ограничивает лимитами, а тупо кидает эксепшн о_О.

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

Задефайни.
Вот Alv показад тебе в одну строчку.

Tanger ★★★★★
()
Ответ на: комментарий от aho

int qRound ( qreal value )?

возвращает:

{ return d >= 0.0 ? int(d + qreal(0.5)) : int(d - int(d-1) + qreal(0.5)) + int(d-1); }

Зачем так, не проще ли (int)floor(x+.5)? Переносимость?

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

> Зачем так, не проще ли (int)floor(x+.5)?

floor - дополнительный вызов функции, вероятно посчитали, что без нее будет быстрее

aho
()
Ответ на: комментарий от AIv
#include <climits>
#include <cmath>
#include <cstdio>

inline int alv( double x )
{
	return isinf(x) ? ( x<0 ? INT_MIN : INT_MAX ) : (int)floor(x+.5);
}

int main()
{
	double x = 1000000000000000000000000000.;
	int i = alv( x );

	printf( "%d\n", i );
}
./a.out 
-2147483648
aho
()
Ответ на: комментарий от aho

И правда... тогда чуть сложнее

isinf(x) ?( x<0 ? INT_MIN : INT_MAX ) : ( x<INT_MIN ? INT_MIN : (x>INT_MAX ? INT_MAX : (int)x ) ) )

ну или еще куча аналогичных вариантов.

AIv ★★★★★
()
Ответ на: комментарий от pathfinder

Вообще то floor наск я помню работает стабильнее и предсказуемее чем приведение к инту. С приведением там бывают грабли, т.е. int будет но не оч понятно какой (верхний или нижний)

AIv ★★★★★
()

> бесконечности для int нету, так что надо тупо обрезать по [INT_MIN; INT_MAX]


А что ты будешь делать с полученными INT_MIN/INT_MAX?

А с NaN?

Может, хватит херней заниматься?

LamerOk ★★★★★
()
Ответ на: комментарий от Obey-Kun

он имеет ввиду, что подобное преобразование вообще не должно производится в случае, если размера int не хватает

aho
()
Ответ на: комментарий от aho

В моём случае нужно как раз такое преобразование. Во всяком случае, при конвертации inf в INT_MAX, всё будет в порядке.

Ну в общем-то не суть, уже всё сделал чуть иначе.

Obey-Kun ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.