8

i've tried this significant figures query from this blog (https://www.garysieling.com/blog/postgres-significant-figures-pg_size_pretty).

But it seems have fixed decimal digit on it.

SELECT FLOOR(5.4321/(10 ^ FLOOR(log(5.4321)-1))) * (10 ^ FLOOR(log(5.4321)-1))

The result from the query above is 5.4. How can i achieve query to create these results?

number | sigfig
5.4321 | 5.43
10.987 | 10.9
550.75 | 550
9850.5 | 9850
ect

Thank you for you help brothers!

3 Answers 3

11

You can use the following function to round to a number of significant digits:

CREATE OR REPLACE FUNCTION sig_digits(n anyelement, digits int) 
RETURNS numeric
AS $$
    SELECT CASE
        WHEN n=0 THEN 0
        ELSE round(n, digits - 1 - floor(log(abs(n)))::int)
    END
$$ LANGUAGE sql IMMUTABLE STRICT;

Compared to Laurenz' answer this has the following differences:

  • the results are rounded, not floored (e.g. sig_digits(15, 1) is 20, not 10)
  • the function takes arbitrary types as first argument (like floats), not only numerics
  • it's faster, because it avoids calling log on numeric (which is slow) if possible and only calls log once
  • it returns pretty results without an unnecessary amount of trailing zeros.
  • it handles zero inputs
Sign up to request clarification or add additional context in comments.

3 Comments

You should use floor(log(abs(n))) so negatives numbers works too.
select case when n is null then null when n = 0 then 0 else round(n, digits - 1 - floor(log(abs(n)))::int) end;
@AdamGering I added handling for the zero case. Nulls work without extra changes in my tests, so I didn't add an extra case for that.
1

To provide a more general answer to this question, I suggest that you use the following function where the number of significant digits is variable:

CREATE FUNCTION significant_digits(n numeric, digits integer) RETURNS numeric
   LANGUAGE sql IMMUTABLE STRICT AS
'SELECT floor(n / (10 ^ floor(log(n) - digits + 1)))
        * (10 ^ floor(log(n) - digits + 1))';

Then you get the following:

test=> SELECT significant_digits(5.4321, 3);
 significant_digits 
--------------------
 5.4300000000000000
(1 row)

test=> SELECT significant_digits(9.87654, 3);
 significant_digits 
--------------------
 9.8700000000000000
(1 row)

Note that the formula does not round as the blog post claims, but truncate.

2 Comments

wow, thank you brother, but how can i get just the important number only, without the zeros? 5.4300000000000000 -> 5.43
Cast to text and apply trim(trailing '0' from ...) to the result.
0

Example of rounding count(status) to Most significant digit:

select count(status),
  round(count(status) / pow(10, trunc(log(count(status))) ) ) * pow(10, trunc(log(count(status))) ) 
  from  some_table;

Eg. 1234 => 1000
    987  => 900

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.