какое-то количество значений влево, и при этом гарантированно не потерять данные?
А то вот (к примеру, если двигаю на 32)
SELECT
1000000000000000000000000000000000000000000000000000000000000000000000000000001::NUMERIC / power(10::numeric, 32::numeric)
-
1000000000000000000000000000000000000000000000000000000000000000000000000000000::NUMERIC
/ power(10::numeric, 32::numeric);
возвращает 0.
А должно возвращать 0.00000000000000000000000000000001
Вот это должно работать (если $2 в интервале от -1000 до 1000): PREPARE foo(numeric, int) AS SELECT $1 * round(10.0, greatest(-$2, 0)) ^ $2; EXECUTE foo(1000000000000000000000000000000000000000000000000000000000000000000000000000001, -32); -- Ну или PREPARE foo(numeric, int) AS SELECT $1 * round(10.0, abs($2)) ^ $2; Но, вообще, я не вижу, чтобы эти (крайние) случаи были где-то документированы (что, казалось бы, означает, что это может кто-нибудь "исправить" (не в ту сторону) хоть в следующей minor version). ;(
Мой пример был скорее про то, что очевидно приходящее в голову решение «сдвинуть на n знаков – это разделить на 10^n». Ваши слова, что “default scale – 16” как-то... не очень логично следуют из документации. Которая говорит, что Specifying: NUMERIC without any precision or scale creates an “unconstrained numeric” column in which numeric values of any length can be stored, up to the implementation limits. Ан нет, не unconstrained. Если мы такой методикой делим на 10^n (10^32 в нашем примере), самая младшая единичка куда-то теряется, как будто и правда scale = 16.
Там ещё написано, что "Calculations with numeric values yield exact results where possible, e.g., addition, subtraction, multiplication." Division и power() в списке нет, обратите внимание. Ну и да, написано-то "values of any length can be stored" (т.е. "up to 131072 digits before the decimal point; up to 16383 digits after the decimal point", см. таблицу выше в документации), но про точность вычислений с ним там ничего не сказано. И получается, что constrained numeric в некоторых ситуациях точнее, чем unconstrained. Если Вам всё это очень важно — можете начать thread в -general или -hackers — может, что-то из этого и выйдет...
Это понятно. Я потому и подумал именно про конкретную задачу – не просто про деление общего вида (которое в каких-то случаях может, и могло бы автоматически детектировать-менять scale; но в общем случае это бессмысленно), а про смену десятичного порядка. Это могло бы быть отдельной и более умной функцией (вот как иногда реализуют функции log, а рядом с ними реализуют функцию log10). Задумался, вдруг я чего-то не знаю, и такая функция уже есть. Но ладно, спасибо за помощь. На -hackers, пожалуй, не решусь, но ситуацию буду знать. Я подумал-подумал и для своих задач явно указал numeric(158, 79) – должно хватить.
В принципе, я Вам показал работающие до scale < 1000 решения. > На -hackers, пожалуй, не решусь, но ситуацию буду знать. А жаль. ;) Было бы неплохо, если бы это либо документировали, либо сделали поведение "крайних" случаев более логичным, IMHO.
Обсуждают сегодня