LINUX.ORG.RU

«уместить» uint64 в int, данные не важны

 ,


0

2

Суть в том что определенная библиотека работает только с обычными int.

Данные не важны потому что абстрактные «максимум» и «текущее значение», и эти абстрактные данные только в uint64.

Как лучше сделать. Делить uint64 на 2 пока не уместится в std::numeric_limits<int>::max()?

★★★★★

Ответ на: комментарий от bhfq

Если кратко - нормализируешь не к 0..1 а к твоему диапазону допустимых значений

На простом примере: У тебя значения от 0 до 100, ты их хочешь нормализовать к значениям от 5 до 20. Тогда ты виртуально растягиваешь ось своих исходных значений таким образом, чтобы ее минимум оказался на минимуме требуемой области, а максимум на максимуме:

|-------------------------------|
0                              100
    |------------|
    5            20

|-------------------------------|
0                              100
|-------------------------------|
5                              20

Все остальные значения мапятся на новую область возможных значений автоматически.

Например у тебя было число 50 изначальных «попугаев». При новом мапинге оно будет на середине допустимых значений, т.е:

20 - 5 = 15 всего значений
15 / 2 = 7.5 середина

Следовательно твои «виртуальные» 50 нормализуются к 7.5.

int32_t normalize(uint64_t val) {
    static const __int128 sourcerange  = (         UINT64_MAX - 0);
    static const __int128 allowedrange = ((int64_t)INT32_MAX - INT32_MIN);
    return (int32_t)(val * allowedrange / sourcerange + INT32_MIN);
}

Проверяем на граничных случаях:

printf("%d %d %d\n", normalize(0), normalize(UINT64_MAX / 2), normalize(UINT64_MAX));

-2147483648 -1 2147483647
PPP328 ★★★★ ()
Ответ на: комментарий от PPP328

Мда. Оба предложенных в теме варианта так и не подходят. Твой сабж же вообще __int128 такого на винде нет. Да и сделай normalize на рандомных значениях что умещаются в int. http://cpp.sh/6bllw

Все таки моя оригинальная задумка делить abst_maximum N раз пока тот не уместится в std::numeric_limits<int>::max(), а затем и abst_current делить такое же количество раз вполне рабочий вариант.

Хотя в математике наверное есть какое-то умное слово и простое решение для этого.

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

Да и сделай normalize на рандомных значениях что умещаются в int. http://cpp.sh/6bllw

И что не так? Посмотри, во сколько раз отличается шкала uint64 и int32. Твои несколько сотен тысяч для этой шкалы меньше единицы.

такого на винде нет.

На винфак. Или пользуйся mingw вместо своего убожества.

Хотя в математике наверное есть какое-то умное слово и простое решение для этого.

Нормализация и масштабирование. Как раз то, что я показал

PPP328 ★★★★ ()
Ответ на: комментарий от i-rinat

Извлеки квадратный корень и подели на два.

А почему так можно? Во-первых, так ведь линейная функция преобразуется в квадратный корень, а во-вторых, что если у него, например, его abst_maximum на самом деле равен INT_MAX?

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

Ну, собственно, PPP328 и написал «математически». Можно перефразировать:

пусть limit = std::numeric_limits<int>::max()
тогда x / limit == abst_current / abst_maximum
значит x == (abst_current * limit) / abst_maximum


Только он учёл полный диапазон int, а не только от 0 до std::numeric_limits<int>::max(). Это, конечно, лучше с точки зрения потери точности, но только если допустимо ставить положительным значениям в соответствие отрицательные. А если недопустимо или допустима бо́льшая потеря точности, то в строке (abst_current * limit) / abst_maximum, limit достаточно привести к uint64_t, а результат преобразовать в int.

Без __int128 в любом случае можно обойтись, только кода будет больше.

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

А почему так можно?

Там всё равно всё эмпирически. Никаких деталей о задаче ТС не предоставил, поэтому все гадают. Кому-то кажется нормальным просто отбросить 32 младших бита. Кому-то нет. Ты, например, поднял вопрос о значениях. До этого все считали, что они занимают все значащие биты 64-битного числа.

i-rinat ★★★★★ ()

Не знаю уж как проще объяснить. Выглядит это как масштабирование.

https://i.imgur.com/XbyroS7.png (пропорции естественно не верные)

Так вот допустим что библиотека рисования этого графика проприетарная и туда лучше не лезть, умеет только int , и на 32 битной сборке он 32 битный. Так как цифры не нужны, а нужны только нарисованные линии логично что их можно масштабировать на этот int.

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

Сделай свой флоатинг поинт тогда. Зафигачь скажем 6 бит в экспоненту и 26 в мантиссу. Так сохранится порядок чисел u64->u32, и более-менее точное значение на низах. Как и с какого бока к интам привести сам уж догадаешься. На «неграфике» можно нарисовать логарифмические полосы, чтобы порядок понимать. Если точность мантиссы не критична, тебе и просто float может сойти, там ее уже 23-24 бита.

anonymous ()