返回给定数字的 N 个有效数字的函数
Posted
技术标签:
【中文标题】返回给定数字的 N 个有效数字的函数【英文标题】:Function to return N significant digits of given number 【发布时间】:2018-11-06 22:34:59 【问题描述】:我看过几个关于这个主题的问题,但答案对我来说似乎没有用。
我必须在 PostgreSQL 10.5 中创建一个返回具有 N 个有效数字的数字的函数。我已经为这个问题尝试了不同的解决方案,但是我遇到了一个特定情况的问题。在示例下方,其中nmNumber
是输入参数的个数,nmSf
是有效位数。
SELECT round(nmNumber * power(10, nmSf-1-floor(log(abs(nmNumber ))))) / power(10, nmSf-1-floor(log(abs(nmNumber)))) result1,
round(nmNumber, cast(-floor(log(abs(nmNumber))) as integer)) result2,
floor(nmNumber / (10 ^ floor(log(nmNumber) - nmSf + 1))) * (10 ^ floor(log(nmNumber) - nmSf + 1)) result3;
如果nmNumber
= 0.0801 和nmSf
= 2 那么:
结果 1 = 0.08;结果2 = 0.08;结果 3 = 0.08
这三个结果是不正确的,因为:
-
小数点后的零不是有效数字。
所有非零数字都有效。
十进制中除零以外的数字后的零很重要。
根据第 3 点,上一个示例的正确结果是:0.080 而不是 0.08,虽然从数学上证明是相同的,但从视觉上我必须得到这个结果。关于如何解决我的问题的一些想法?我想返回VARCHAR
以换取NUMERIC
是要提出的解决方案的一部分。
一些想法或我错过了一些东西。谢谢。
【问题讨论】:
你确定你是意思第3点吗?因为小数点后的尾随零对数值无关紧要... 那么你有答案了吗? 【参考方案1】:这将实现您的要求:
CREATE OR REPLACE FUNCTION f_significant_nr(_nr numeric, _sf int, OUT _nr1 text) AS
$func$
DECLARE
_sign bool; -- record negative sign
_int int; -- length of integral part
_nr_text text; -- intermediate text state
BEGIN
IF _sf < 1 THEN
RAISE EXCEPTION '_sf must be > 0!';
ELSIF _nr IS NULL THEN
RETURN; -- returns NULL
ELSIF _nr = 0 THEN
_nr1 := '0'; RETURN;
ELSIF _sf >= length(translate(_nr::text, '-.','')) THEN -- not enough digits, optional shortcut
_nr1 := _nr; RETURN;
ELSIF abs(_nr) < 1 THEN
_nr1 := COALESCE(substring(_nr::text, '^.*?[1-9]\d' || _sf-1 || ''), _nr::text); RETURN;
ELSIF _nr < 0 THEN -- extract neg sign
_sign := true;
_nr := _nr * -1;
END IF;
_int := trunc(log(_nr))::int + 1; -- <= 0 was excluded above!
IF _sf < _int THEN -- fractional digits not touched
_nr1 := rpad(left(_nr::text, _sf), _int, '0');
ELSE
_nr1 := trunc(_nr)::text;
IF _sf > _int AND (_nr % 1) > 0 THEN -- _sf > _int and we have significant fractional digits
_nr_text := right((_nr % 1)::text, -1); -- remainder: ".123"
_nr1 := _nr1 || COALESCE(substring(_nr_text, '^.*?[1-9]\d' || (_sf - _int - 1)::text || ''), _nr_text);
END IF;
END IF;
IF _sign THEN
_nr1 := '-' || _nr1;
END IF;
END
$func$ LANGUAGE plpgsql;
dbfiddle here - 带有测试用例。
处理您扔给它的所有内容,包括NULL
、0
、0.000
或负数。
但我对您评论的第 3 点表示怀疑。
【讨论】:
【参考方案2】:postgres 知道如何做到这一点(即使是第 3 点),你只需要以正确的方式问它。
create or replace function
sig_fig(num numeric,prec int) returns numeric
language sql as
$$
select to_char($1, '9.'||repeat('9',$2-1)||'EEEE')::numeric
$$;
这会创建一个生成科学的格式字符串 带有 3 位尾数的符号。使用那个 以文本形式获取数字然后将其转换回数字,从而产生具有那么多有效数字的常规数字。
演示:
with v as ( values (3.14159),(1234567),(0.02),(1024),(42),(0.0098765),(-6666) ) select column1 ,sig_fig(column1,3) as "3sf" from v;
column1 | 3sf
-----------+---------
3.14159 | 3.14
1234567 | 1230000
0.02 | 0.0200
1024 | 1020
42 | 42.0
0.0098765 | 0.00988
-6666 | -6670
(7 rows)
【讨论】:
以上是关于返回给定数字的 N 个有效数字的函数的主要内容,如果未能解决你的问题,请参考以下文章
2022-08-06:给定一个数组arr,长度为N,arr中所有的值都在1~K范围上, 你可以删除数字,目的是让arr的最长递增子序列长度小于K。 返回至少删除几个数字能达到目的。 N <= 10^4
2022-06-16:给定一个数组arr,含有n个数字,都是非负数, 给定一个正数k, 返回所有子序列中,累加和最小的前k个子序列累加和。 假设K不大,怎么算最快? 来自亚马逊。
ZZNUOJ_C语言1101:逆序数字(函数专题)(完整代码)