Reputation: 1359
Is there a rounding function oracle to round to a specific number of significant digits?
For example, round 1278 to 1300, round to two significant digits.
Upvotes: 3
Views: 7233
Reputation: 168740
If you want to round a number to a number of significant figures then use @Jeffery Kemp's comment (except you need to subtract 1 from the digits)
TO_NUMBER(TO_CHAR(value, '9.' || LPAD('9',digits - 1,'9') || 'EEEE'))
or @f3lix's answer can be fixed to work for 0
and negative numbers using:
ROUND(value, digits - CASE value WHEN 0 THEN 1 ELSE FLOOR(LOG(10, ABS(value))) + 1 END)
If you want to format the number to show a number of significant digits then you can take the rounded number and use TO_CHAR
to format it and calculate how many digits should be in the integer- and decimal-parts of the format mask:
SELECT value,
digits,
ROUND(value, digits - CASE value WHEN 0 THEN 1 ELSE FLOOR(LOG(10, ABS(value))) + 1 END)
AS rounded_value,
TO_CHAR(
ROUND(value, digits - CASE value WHEN 0 THEN 1 ELSE FLOOR(LOG(10, ABS(value))) + 1 END),
'FM9'
|| LPAD('0', GREATEST(CASE value WHEN 0 THEN 1 ELSE FLOOR(LOG(10, ABS(value))) + 1 END, 1), '0')
|| CASE
WHEN digits > CASE value WHEN 0 THEN 1 ELSE FLOOR(LOG(10, ABS(value))) + 1 END
THEN '.' || LPAD('0', digits - CASE value WHEN 0 THEN 1 ELSE FLOOR(LOG(10, ABS(value))) + 1 END, '0')
END
) AS formatted_value
FROM table_name;
Which, for the sample data:
CREATE TABLE table_name (value, digits) AS
SELECT 1278, 2 FROM DUAL UNION ALL
SELECT 1234.56789, 2 FROM DUAL UNION ALL
SELECT 1234.56789, 4 FROM DUAL UNION ALL
SELECT 1234.56789, 5 FROM DUAL UNION ALL
SELECT 1234.56789, 6 FROM DUAL UNION ALL
SELECT 1000, 2 FROM DUAL UNION ALL
SELECT 1000, 5 FROM DUAL UNION ALL
SELECT 0.1234, 2 FROM DUAL UNION ALL
SELECT 0.1234, 8 FROM DUAL UNION ALL
SELECT 3, 2 FROM DUAL UNION ALL
SELECT 3.12345, 2 FROM DUAL UNION ALL
SELECT 0, 2 FROM DUAL UNION ALL
SELECT -3.12345, 2 FROM DUAL UNION ALL
SELECT -1.2345e-5, 3 FROM DUAL UNION ALL
SELECT 99.997, 2 FROM DUAL
Outputs:
VALUE | DIGITS | ROUNDED_VALUE | FORMATTED_VALUE |
---|---|---|---|
1278 | 2 | 1300 | 1300 |
1234.56789 | 2 | 1200 | 1200 |
1234.56789 | 4 | 1235 | 1235 |
1234.56789 | 5 | 1234.6 | 1234.6 |
1234.56789 | 6 | 1234.57 | 1234.57 |
1000 | 2 | 1000 | 1000 |
1000 | 5 | 1000 | 1000.0 |
.1234 | 2 | .12 | 0.12 |
.1234 | 8 | .1234 | 0.12340000 |
3 | 2 | 3 | 3.0 |
3.12345 | 2 | 3.1 | 3.1 |
0 | 2 | 0 | 0.0 |
-3.12345 | 2 | -3.1 | -3.1 |
-.000012345 | 3 | -.0000123 | -0.0000123 |
99.997 | 2 | 100 | 100 |
Upvotes: 0
Reputation: 29885
Try ROUND(x, d - FLOOR(LOG(10, x)) - 1)
where d
is the number of significant digits and x
is the value to be rounded.
Example:
SELECT
ROUND(x, d - FLOOR(LOG(10, x)) - 1)
FROM (SELECT 1278 x, 2 d FROM DUAL UNION ALL
SELECT 0.1234 x, 2 d FROM DUAL );
Upvotes: 4
Reputation: 10941
Just off the top of my head, probably a subject to further optimization :)
16:54:16 SYSTEM@dwal> select to_number(to_char(1278, '9.9EEEE')) t from dual;
T
----------
1300
Elapsed: 00:00:00.01
16:54:34 SYSTEM@dwal> select to_number(to_char(.1234, '9.9EEEE')) t from dual;
T
----------
.12
Elapsed: 00:00:00.01
Upvotes: 3