转:http://stackoverflow/questions/202302/rounding-to-an-arbitrary-number-of-significant-digits
Q:
How can you round any number (not just integers > 0) to N significant digits?
For example, if I want to round to 3 significant digits, I'm looking for a formula that could take:
1,239,451 and return 1,240,000
12.1257 and return 12.1
.0681 and return .0681
5 and return 5
Naturally the algorithm should not be hard-coded to only handle N of 3, although that would be a start.
A:
15 Answers
active
oldest
votes
|
up vote
82
down vote
accepted
|
Here's the same code in Java without the 12.100000000000001 bug other answers have
I also removed repeated code, changed power to a type integer to prevent floating issues when n - d is done, and made the long intermediate more clear
The bug was caused by multiplying a large number with a small number. Instead I divide two numbers of similar size.
EDIT Fixed more bugs. Added check for 0 as it would result in NaN. Made the function actually work with negative numbers (The original code doesn't handle negative numbers because a log of a negative number is a complex number)
public static double roundToSignificantFigures(double num, int n) {
if(num == 0) {
return 0;
}
final double d = Math.ceil(Math.log10(num < 0 ? -num: num));
final int power = n - (int) d;
final double magnitude = Math.pow(10, power);
final long shifted = Math.round(num*magnitude);
return shifted/magnitude;
}
|
share
improve this answer
|
edited Jan 17 '14 at 0:42
|
answered
Oct 17 '09 at 0:20
Pyrolistical
14.2k
12
58
87
| |
| |
|
|
Your code is indeed much nicer. –
Claudiu
Dec 14 '09 at 23:41
| |
|
Thanks for accepting my answer. I just realized my answer is more than a year after the question. This is one of the reasons why stackoverflow is so cool. You can find useful information! –
Pyrolistical
May 21 '10 at 22:45
| |
|
Note that this may fail slightly for values close to the round limit. For example rounding 1.255 to 3 significant digits should return 1.26 but returns 1.25. That is because 1.255 * 100.0 is 125.499999... But this is to be expected when working with doubles –
cquezel
Nov 22 '14 at 17:10
|
add a comment
|
|
up vote
15
down vote
|
SUMMARY:
double roundit(double num, double N)
{
double d = log10(num);
double power;
if (num > 0)
{
d = ceil(d);
power = -(d-N);
}
else
{
d = floor(d);
power = -(d-N);
}
return (int)(num * pow(10.0, power) + 0.5) * pow(10.0, -power);
}
So you need to find the decimal place of the first non-zero digit, then save the next N-1 digits, then round the Nth digit based on the rest.
We can use log to do the first.
log 1239451 = 6.09
log 12.1257 = 1.08
log 0.0681 = -1.16
So for numbers > 0, take the ceil of the log. For numbers < 0, take the floor of the log.
Now we have the digit d: 7 in the first case, 2 in the 2nd, -2 in the 3rd.
We have to round the (d-N)th digit. Something like:
double roundedrest = num * pow(10, -(d-N));
pow(1239451, -4) = 123.9451
pow(12.1257, 1) = 121.257
pow(0.0681, 4) = 681
Then do the standard rounding thing:
roundedrest = (int)(roundedrest + 0.5);
And undo the pow.
roundednum = pow(roundedrest, -(power))
Where power is the power calculated above.
About accuracy: Pyrolistical's answer is indeed closer to the real result. But note that you can't represent 12.1 exactly in any case. If you print the answers as follows:
System.out.println(new BigDecimal(n));
The answers are:
Pyro's: 12.0999999999999996447286321199499070644378662109375
Mine: 12.10000000000000142108547152020037174224853515625
Printing 12.1 directly: 12.0999999999999996447286321199499070644378662109375
So, use Pyro's answer!
|
share
improve this answer
|
edited Dec 16 '09 at 3:59
|
answered
Oct 14 '08 at 18:47
Claudiu
73.8k
70
263
447
| |
| |
|
|
Had some minor bugs right when it was accepted, but it's fixed now. –
Claudiu
Oct 14 '08 at 19:01
| |
|
This algorithm seems prone to floating point errors. When implemented with JavaScript, I get: 0.06805 -> 0.06810000000000001 and 12.1 -> 12.100000000000001 –
Ates Goral
Oct 14 '08 at 19:30
| |
|
This code in Java produces 12.100000000000001 and this is using 64-bit doubles which can present 12.1 exactly. –
Pyrolistical
Oct 17 '09 at 0:00
| |
|
It doesn't matter if it's 64 bit or 128 bit. You can't represent the fraction 1/10 using a finite sum of powers of 2, and that's how floating point numbers are represented –
Claudiu
Oct 17 '09 at 17:02
| |
|
for those chiming in, basically Pyrolistical's answer is more precise than mine so that the floating point number printing algorithm prints '12.1' instead of '12.100000000000001'. his answer is better, even tho i was technically correct that you can't represent '12.1' exactly. –
Claudiu
Mar 6 '11 at 5:20
|
show 3 more comments
|
|
up vote
10
down vote
|
Here's a short and sweet JavaScript implementation:
function sigFigs(n, sig) {
var mult = Math.pow(10, sig - Math.floor(Math.log(n) / Math.LN10) - 1);
return Math.round(n * mult) / mult;
}
alert(sigFigs(1234567, 3)); // Gives 1230000
alert(sigFigs(0.06805, 3)); // Gives 0.0681
alert(sigFigs(5, 3)); // Gives 5
|
share
improve this answer
|
edited Oct 15 '08 at 4:09
|
answered
Oct 14 '08 at 19:20
Ates Goral
59.9k
14
93
154
| |
| |
|
|
but 12.1257 gives 12.126 –
Pyrolistical
Oct 17 '09 at 0:03
| |
|
Yes, that's valid rounding. –
Ates Goral
Oct 17 '09 at 22:47
| |
|
Nice answer Ates. Perhaps add a trigger to return 0 if n==0 :) –
sscirrus
Oct 22 '11 at 1:56
| |
|
PHP port for the lazy: gist.github/anonymous/9922298 –
Mahn
Apr 1 '14 at 20:20
|
add a comment
|
|
up vote
10
down vote
|
Isn't the "short and sweet" JavaScript implementation
Number(n).toPrecision(sig)
e.g.
alert(Number(12345).toPrecision(3)
?
Sorry, I'm not being facetious here, it's just that using the "roundit" function from Claudiu and the .toPrecision in JavaScript gives me different results but only in the rounding of the last digit.
JavaScript:
Number(8.14301).toPrecision(4) == 8.143
.NET
roundit(8.14301,4) == 8.144
|
share
improve this answer
|
answered
Apr 8 '09 at 15:26
Justin Wignall
2,306
9
18
| |
| |
|
|
Number(814301).toPrecision(4) == "8.143e+5". Generally not what you want if you're showing this to users. –
Zaz
May 4 at 22:48
| |
|
Very true Josh yes, I would generally recommend .toPrecision() only for decimal numbers and the accepted answer (with edit) should be used/reviewed as per your individual requirements. –
Justin Wignall
May 5 at 19:53
|
add a comment
|
|
up vote
6
down vote
|
Pyrolistical's (very nice!) solution still has an issue. The maximum double value in Java is on the order of 10^308, while the minimum value is on the order of 10^-324. Therefore, you can run into trouble when applying the function roundToSignificantFigures to something that's within a few powers of ten of Double.MIN_VALUE. For example, when you call
roundToSignificantFigures(1.234E-310, 3);
then the variable power will have the value 3 - (-309) = 312. Consequently, the variable magnitudewill become Infinity, and it's all garbage from then on out. Fortunately, this is not an insurmountable problem: it is only the factor magnitude that's overflowing. What really matters is the product num * magnitude, and that does not overflow. One way of resolving this is by breaking up the multiplication by the factor magintude into two steps:
public static double roundToNumberOfSignificantDigits(double num, int n) {
final double maxPowerOfTen = Math.floor(Math.log10(Double.MAX_VALUE));
if(num == 0) {
return 0;
}
final double d = Math.ceil(Math.log10(num < 0 ? -num: num));
final int power = n - (int) d;
double firstMagnitudeFactor = 1.0;
double secondMagnitudeFactor = 1.0;
if (power > maxPowerOfTen) {
firstMagnitudeFactor = Math.pow(10.0, maxPowerOfTen);
secondMagnitudeFactor = Math.pow(10.0, (double) power - maxPowerOfTen);
} else {
firstMagnitudeFactor = Math.pow(10.0, (double) power);
}
double toBeRounded = num * firstMagnitudeFactor;
toBeRounded *= secondMagnitudeFactor;
final long shifted = Math.round(toBeRounded);
double rounded = ((double) shifted) / firstMagnitudeFactor;
rounded /= secondMagnitudeFactor;
return rounded;
}
|
share
improve this answer
|
answered
Nov 19 '10 at 1:17
Thomas Becker
61
1
1
| |
| |
|
|
Whoa, rounding at the edge of the universe! –
Pyrolistical
May 7 '12 at 18:30
|
add a comment
|
|
up vote
5
down vote
|
How about this java solution :
double roundToSignificantFigure(double num, int precision){
return new BigDecimal(num)
.round(new MathContext(precision, RoundingMode.HALF_EVEN))
.doubleValue();
}
|
share
improve this answer
|
answered
Aug 10 '10 at 8:00
wolfgang grinfeld
51
1
1
| |
| |
|
|
+1 clean and nice solution –
cetnar
Feb 4 '11 at 12:14
|
add a comment
|
|
up vote
3
down vote
|
Here is a modified version of Ates' JavaScript that handles negative numbers.
function sigFigs(n, sig) {
if ( n === 0 )
return 0
var mult = Math.pow(10,
sig - Math.floor(Math.log(n < 0 ? -n: n) / Math.LN10) - 1);
return Math.round(n * mult) / mult;
}
|
share
improve this answer
|
answered
Jun 4 '10 at 16:18
Jason Swank
31
1
| |
| |
add a comment
|
|
up vote
1
down vote
|
Have you tried just coding it up the way you'd do it by hand?
- Convert the number to a string
- Starting at the beginning of the string, count digits - leading zeroes aren't significant, everything else is.
- When you get to the "nth" digit, peek ahead at the next digit and if it's 5 or higher, round up.
- Replace all of the trailing digits with zeroes.
|
share
improve this answer
|
answered
Oct 14 '08 at 18:52
Mark Bessey
14.6k
3
29
52
| |
| |
add a comment
|
|
up vote
1
down vote
|
[Corrected, 2009-10-26]
Essentially, for N significant fractional digits:
• Multiply the number by 10N • Add 0.5 • Truncate the fraction digits (i.e., truncate the result into an integer) • Divide by 10N
For N significant integral (non-fractional) digits:
• Divide the number by 10N • Add 0.5 • Truncate the fraction digits (i.e., truncate the result into an integer) • Multiply by 10N
You can do this on any calculator, for example, that has an "INT" (integer truncation) operator.
|
share
improve this answer
|
edited Oct 26 '09 at 21:52
|
answered
Oct 17 '09 at 0:41
David R Tribble
5,525
1
16
36
| |
| |
|
|
Nope. Read the question again. 1239451 with 3 sig figs using your algorithm would incorrectly yield 123951 –
Pyrolistical
Oct 20 '09 at 18:06
| |
|
Yep, I corrected it to distinguish between rounding to a fractional number of digits (to the right of the decimal point) versus an integral number of digits (to the left). –
David R Tribble
Oct 26 '09 at 21:53
|
add a comment
|
|
up vote
1
down vote
|
/**
* Set Significant Digits.
* @param value value
* @param digits digits
* @return
*/
public static BigDecimal setSignificantDigits(BigDecimal value, int digits) {
//# Start with the leftmost non-zero digit (e.g. the "1" in 1200, or the "2" in 0.0256).
//# Keep n digits. Replace the rest with zeros.
//# Round up by one if appropriate.
int p = value.precision();
int s = value.scale();
if (p < digits) {
value = value.setScale(s + digits - p); //, RoundingMode.HALF_UP
}
value = value.movePointRight(s).movePointLeft(p - digits).setScale(0, RoundingMode.HALF_UP)
.movePointRight(p - digits).movePointLeft(s);
s = (s > (p - digits)) ? (s - (p - digits)) : 0;
return value.setScale(s);
}
|
share
improve this answer
|
answered
Jun 22 '10 at 0:25
Valeri Shibaev
11
1
| |
| |
add a comment
|
|
up vote
1
down vote
|
Here is Pyrolistical's (currently top answer) code in Visual Basic.NET, should anyone need it:
Public Shared Function roundToSignificantDigits(ByVal num As Double, ByVal n As Integer) As Double
If (num = 0) Then
Return 0
End If
Dim d As Double = Math.Ceiling(Math.Log10(If(num < 0, -num, num)))
Dim power As Integer = n - CInt(d)
Dim magnitude As Double = Math.Pow(10, power)
Dim shifted As Double = Math.Round(num * magnitude)
Return shifted / magnitude
End Function
|
share
improve this answer
|
answered
Jun 21 '11 at 16:10
Michael Zlatkovsky
670
6
10
| |
| |
add a comment
|
|
up vote
1
down vote
|
This came 5 years late, but though I'll share for others still having the same issue. I like it because it's simple and no calculations on the code side. See Built in methods for displaying Significant figures for more info.
This is if you just want to print it out.
public String toSignificantFiguresString(BigDecimal bd, int significantFigures){
return String.format("%."+significantFigures+"G", bd);
}
This is if you want to convert it:
public BigDecimal toSignificantFigures(BigDecimal bd, int significantFigures){
String s = String.format("%."+significantFigures+"G", bd);
BigDecimal result = new BigDecimal(s);
return result;
}
Here's an example of it in action:
BigDecimal bd = toSignificantFigures(BigDecimal.valueOf(0.0681), 2);
|
share
improve this answer
|
answered
Oct 22 '13 at 0:07
JackDev
2,671
3
21
41
| |
| |
add a comment
|
|
up vote
0
down vote
|
This is one that I came up with in VB:
Function SF(n As Double, SigFigs As Integer)
Dim l As Integer = n.ToString.Length
n = n / 10 ^ (l - SigFigs)
n = Math.Round(n)
n = n * 10 ^ (l - SigFigs)
Return n
End Function
|
share
improve this answer
|
answered
Jun 1 '13 at 16:05
SomeGuy
1
| |
| |
add a comment
|
|
up vote
0
down vote
|
JavaScript:
Number( my_number.toPrecision(3) );
The Number function will change output of the form "8.143e+5" to "814300".
|
share
improve this answer
|
answered
May 4 at 22:56
Zaz
6,611
3
26
43
| |
| |
add a comment
|
|
up vote
-1
down vote
|
public static double roundToSignificantDigits(double num, int n) {
return Double.parseDouble(new java.util.Formatter().format("%." + (n - 1) + "e", num).toString());
}
This code uses the inbuilt formatting function which is turned to a rounding function
|
转:http://stackoverflow/questions/202302/rounding-to-an-arbitrary-number-of-significant-digits
Q:
How can you round any number (not just integers > 0) to N significant digits?
For example, if I want to round to 3 significant digits, I'm looking for a formula that could take:
1,239,451 and return 1,240,000
12.1257 and return 12.1
.0681 and return .0681
5 and return 5
Naturally the algorithm should not be hard-coded to only handle N of 3, although that would be a start.
A:
15 Answers
active
oldest
votes
|
up vote
82
down vote
accepted
|
Here's the same code in Java without the 12.100000000000001 bug other answers have
I also removed repeated code, changed power to a type integer to prevent floating issues when n - d is done, and made the long intermediate more clear
The bug was caused by multiplying a large number with a small number. Instead I divide two numbers of similar size.
EDIT Fixed more bugs. Added check for 0 as it would result in NaN. Made the function actually work with negative numbers (The original code doesn't handle negative numbers because a log of a negative number is a complex number)
public static double roundToSignificantFigures(double num, int n) {
if(num == 0) {
return 0;
}
final double d = Math.ceil(Math.log10(num < 0 ? -num: num));
final int power = n - (int) d;
final double magnitude = Math.pow(10, power);
final long shifted = Math.round(num*magnitude);
return shifted/magnitude;
}
|
share
improve this answer
|
edited Jan 17 '14 at 0:42
|
answered
Oct 17 '09 at 0:20
Pyrolistical
14.2k
12
58
87
| |
| |
|
|
Your code is indeed much nicer. –
Claudiu
Dec 14 '09 at 23:41
| |
|
Thanks for accepting my answer. I just realized my answer is more than a year after the question. This is one of the reasons why stackoverflow is so cool. You can find useful information! –
Pyrolistical
May 21 '10 at 22:45
| |
|
Note that this may fail slightly for values close to the round limit. For example rounding 1.255 to 3 significant digits should return 1.26 but returns 1.25. That is because 1.255 * 100.0 is 125.499999... But this is to be expected when working with doubles –
cquezel
Nov 22 '14 at 17:10
|
add a comment
|
|
up vote
15
down vote
|
SUMMARY:
double roundit(double num, double N)
{
double d = log10(num);
double power;
if (num > 0)
{
d = ceil(d);
power = -(d-N);
}
else
{
d = floor(d);
power = -(d-N);
}
return (int)(num * pow(10.0, power) + 0.5) * pow(10.0, -power);
}
So you need to find the decimal place of the first non-zero digit, then save the next N-1 digits, then round the Nth digit based on the rest.
We can use log to do the first.
log 1239451 = 6.09
log 12.1257 = 1.08
log 0.0681 = -1.16
So for numbers > 0, take the ceil of the log. For numbers < 0, take the floor of the log.
Now we have the digit d: 7 in the first case, 2 in the 2nd, -2 in the 3rd.
We have to round the (d-N)th digit. Something like:
double roundedrest = num * pow(10, -(d-N));
pow(1239451, -4) = 123.9451
pow(12.1257, 1) = 121.257
pow(0.0681, 4) = 681
Then do the standard rounding thing:
roundedrest = (int)(roundedrest + 0.5);
And undo the pow.
roundednum = pow(roundedrest, -(power))
Where power is the power calculated above.
About accuracy: Pyrolistical's answer is indeed closer to the real result. But note that you can't represent 12.1 exactly in any case. If you print the answers as follows:
System.out.println(new BigDecimal(n));
The answers are:
Pyro's: 12.0999999999999996447286321199499070644378662109375
Mine: 12.10000000000000142108547152020037174224853515625
Printing 12.1 directly: 12.0999999999999996447286321199499070644378662109375
So, use Pyro's answer!
|
share
improve this answer
|
edited Dec 16 '09 at 3:59
|
answered
Oct 14 '08 at 18:47
Claudiu
73.8k
70
263
447
| |
| |
|
|
Had some minor bugs right when it was accepted, but it's fixed now. –
Claudiu
Oct 14 '08 at 19:01
| |
|
This algorithm seems prone to floating point errors. When implemented with JavaScript, I get: 0.06805 -> 0.06810000000000001 and 12.1 -> 12.100000000000001 –
Ates Goral
Oct 14 '08 at 19:30
| |
|
This code in Java produces 12.100000000000001 and this is using 64-bit doubles which can present 12.1 exactly. –
Pyrolistical
Oct 17 '09 at 0:00
| |
|
It doesn't matter if it's 64 bit or 128 bit. You can't represent the fraction 1/10 using a finite sum of powers of 2, and that's how floating point numbers are represented –
Claudiu
Oct 17 '09 at 17:02
| |
|
for those chiming in, basically Pyrolistical's answer is more precise than mine so that the floating point number printing algorithm prints '12.1' instead of '12.100000000000001'. his answer is better, even tho i was technically correct that you can't represent '12.1' exactly. –
Claudiu
Mar 6 '11 at 5:20
|
show 3 more comments
|
|
up vote
10
down vote
|
Here's a short and sweet JavaScript implementation:
function sigFigs(n, sig) {
var mult = Math.pow(10, sig - Math.floor(Math.log(n) / Math.LN10) - 1);
return Math.round(n * mult) / mult;
}
alert(sigFigs(1234567, 3)); // Gives 1230000
alert(sigFigs(0.06805, 3)); // Gives 0.0681
alert(sigFigs(5, 3)); // Gives 5
|
share
improve this answer
|
edited Oct 15 '08 at 4:09
|
answered
Oct 14 '08 at 19:20
Ates Goral
59.9k
14
93
154
| |
| |
|
|
but 12.1257 gives 12.126 –
Pyrolistical
Oct 17 '09 at 0:03
| |
|
Yes, that's valid rounding. –
Ates Goral
Oct 17 '09 at 22:47
| |
|
Nice answer Ates. Perhaps add a trigger to return 0 if n==0 :) –
sscirrus
Oct 22 '11 at 1:56
| |
|
PHP port for the lazy: gist.github/anonymous/9922298 –
Mahn
Apr 1 '14 at 20:20
|
add a comment
|
|
up vote
10
down vote
|
Isn't the "short and sweet" JavaScript implementation
Number(n).toPrecision(sig)
e.g.
alert(Number(12345).toPrecision(3)
?
Sorry, I'm not being facetious here, it's just that using the "roundit" function from Claudiu and the .toPrecision in JavaScript gives me different results but only in the rounding of the last digit.
JavaScript:
Number(8.14301).toPrecision(4) == 8.143
.NET
roundit(8.14301,4) == 8.144
|
share
improve this answer
|
answered
Apr 8 '09 at 15:26
Justin Wignall
2,306
9
18
| |
| |
|
|
Number(814301).toPrecision(4) == "8.143e+5". Generally not what you want if you're showing this to users. –
Zaz
May 4 at 22:48
| |
|
Very true Josh yes, I would generally recommend .toPrecision() only for decimal numbers and the accepted answer (with edit) should be used/reviewed as per your individual requirements. –
Justin Wignall
May 5 at 19:53
|
add a comment
|
|
up vote
6
down vote
|
Pyrolistical's (very nice!) solution still has an issue. The maximum double value in Java is on the order of 10^308, while the minimum value is on the order of 10^-324. Therefore, you can run into trouble when applying the function roundToSignificantFigures to something that's within a few powers of ten of Double.MIN_VALUE. For example, when you call
roundToSignificantFigures(1.234E-310, 3);
then the variable power will have the value 3 - (-309) = 312. Consequently, the variable magnitudewill become Infinity, and it's all garbage from then on out. Fortunately, this is not an insurmountable problem: it is only the factor magnitude that's overflowing. What really matters is the product num * magnitude, and that does not overflow. One way of resolving this is by breaking up the multiplication by the factor magintude into two steps:
public static double roundToNumberOfSignificantDigits(double num, int n) {
final double maxPowerOfTen = Math.floor(Math.log10(Double.MAX_VALUE));
if(num == 0) {
return 0;
}
final double d = Math.ceil(Math.log10(num < 0 ? -num: num));
final int power = n - (int) d;
double firstMagnitudeFactor = 1.0;
double secondMagnitudeFactor = 1.0;
if (power > maxPowerOfTen) {
firstMagnitudeFactor = Math.pow(10.0, maxPowerOfTen);
secondMagnitudeFactor = Math.pow(10.0, (double) power - maxPowerOfTen);
} else {
firstMagnitudeFactor = Math.pow(10.0, (double) power);
}
double toBeRounded = num * firstMagnitudeFactor;
toBeRounded *= secondMagnitudeFactor;
final long shifted = Math.round(toBeRounded);
double rounded = ((double) shifted) / firstMagnitudeFactor;
rounded /= secondMagnitudeFactor;
return rounded;
}
|
share
improve this answer
|
answered
Nov 19 '10 at 1:17
Thomas Becker
61
1
1
| |
| |
|
|
Whoa, rounding at the edge of the universe! –
Pyrolistical
May 7 '12 at 18:30
|
add a comment
|
|
up vote
5
down vote
|
How about this java solution :
double roundToSignificantFigure(double num, int precision){
return new BigDecimal(num)
.round(new MathContext(precision, RoundingMode.HALF_EVEN))
.doubleValue();
}
|
share
improve this answer
|
answered
Aug 10 '10 at 8:00
wolfgang grinfeld
51
1
1
| |
| |
|
|
+1 clean and nice solution –
cetnar
Feb 4 '11 at 12:14
|
add a comment
|
|
up vote
3
down vote
|
Here is a modified version of Ates' JavaScript that handles negative numbers.
function sigFigs(n, sig) {
if ( n === 0 )
return 0
var mult = Math.pow(10,
sig - Math.floor(Math.log(n < 0 ? -n: n) / Math.LN10) - 1);
return Math.round(n * mult) / mult;
}
|
share
improve this answer
|
answered
Jun 4 '10 at 16:18
Jason Swank
31
1
| |
| |
add a comment
|
|
up vote
1
down vote
|
Have you tried just coding it up the way you'd do it by hand?
- Convert the number to a string
- Starting at the beginning of the string, count digits - leading zeroes aren't significant, everything else is.
- When you get to the "nth" digit, peek ahead at the next digit and if it's 5 or higher, round up.
- Replace all of the trailing digits with zeroes.
|
share
improve this answer
|
answered
Oct 14 '08 at 18:52
Mark Bessey
14.6k
3
29
52
| |
| |
add a comment
|
|
up vote
1
down vote
|
[Corrected, 2009-10-26]
Essentially, for N significant fractional digits:
• Multiply the number by 10N • Add 0.5 • Truncate the fraction digits (i.e., truncate the result into an integer) • Divide by 10N
For N significant integral (non-fractional) digits:
• Divide the number by 10N • Add 0.5 • Truncate the fraction digits (i.e., truncate the result into an integer) • Multiply by 10N
You can do this on any calculator, for example, that has an "INT" (integer truncation) operator.
|
share
improve this answer
|
edited Oct 26 '09 at 21:52
|
answered
Oct 17 '09 at 0:41
David R Tribble
5,525
1
16
36
| |
| |
|
|
Nope. Read the question again. 1239451 with 3 sig figs using your algorithm would incorrectly yield 123951 –
Pyrolistical
Oct 20 '09 at 18:06
| |
|
Yep, I corrected it to distinguish between rounding to a fractional number of digits (to the right of the decimal point) versus an integral number of digits (to the left). –
David R Tribble
Oct 26 '09 at 21:53
|
add a comment
|
|
up vote
1
down vote
|
/**
* Set Significant Digits.
* @param value value
* @param digits digits
* @return
*/
public static BigDecimal setSignificantDigits(BigDecimal value, int digits) {
//# Start with the leftmost non-zero digit (e.g. the "1" in 1200, or the "2" in 0.0256).
//# Keep n digits. Replace the rest with zeros.
//# Round up by one if appropriate.
int p = value.precision();
int s = value.scale();
if (p < digits) {
value = value.setScale(s + digits - p); //, RoundingMode.HALF_UP
}
value = value.movePointRight(s).movePointLeft(p - digits).setScale(0, RoundingMode.HALF_UP)
.movePointRight(p - digits).movePointLeft(s);
s = (s > (p - digits)) ? (s - (p - digits)) : 0;
return value.setScale(s);
}
|
share
improve this answer
|
answered
Jun 22 '10 at 0:25
Valeri Shibaev
11
1
| |
| |
add a comment
|
|
up vote
1
down vote
|
Here is Pyrolistical's (currently top answer) code in Visual Basic.NET, should anyone need it:
Public Shared Function roundToSignificantDigits(ByVal num As Double, ByVal n As Integer) As Double
If (num = 0) Then
Return 0
End If
Dim d As Double = Math.Ceiling(Math.Log10(If(num < 0, -num, num)))
Dim power As Integer = n - CInt(d)
Dim magnitude As Double = Math.Pow(10, power)
Dim shifted As Double = Math.Round(num * magnitude)
Return shifted / magnitude
End Function
|
share
improve this answer
|
answered
Jun 21 '11 at 16:10
Michael Zlatkovsky
670
6
10
| |
| |
add a comment
|
|
up vote
1
down vote
|
This came 5 years late, but though I'll share for others still having the same issue. I like it because it's simple and no calculations on the code side. See Built in methods for displaying Significant figures for more info.
This is if you just want to print it out.
public String toSignificantFiguresString(BigDecimal bd, int significantFigures){
return String.format("%."+significantFigures+"G", bd);
}
This is if you want to convert it:
public BigDecimal toSignificantFigures(BigDecimal bd, int significantFigures){
String s = String.format("%."+significantFigures+"G", bd);
BigDecimal result = new BigDecimal(s);
return result;
}
Here's an example of it in action:
BigDecimal bd = toSignificantFigures(BigDecimal.valueOf(0.0681), 2);
|
share
improve this answer
|
answered
Oct 22 '13 at 0:07
JackDev
2,671
3
21
41
| |
| |
add a comment
|
|
up vote
0
down vote
|
This is one that I came up with in VB:
Function SF(n As Double, SigFigs As Integer)
Dim l As Integer = n.ToString.Length
n = n / 10 ^ (l - SigFigs)
n = Math.Round(n)
n = n * 10 ^ (l - SigFigs)
Return n
End Function
|
share
improve this answer
|
answered
Jun 1 '13 at 16:05
SomeGuy
1
| |
| |
add a comment
|
|
up vote
0
down vote
|
JavaScript:
Number( my_number.toPrecision(3) );
The Number function will change output of the form "8.143e+5" to "814300".
|
share
improve this answer
|
answered
May 4 at 22:56
Zaz
6,611
3
26
43
| |
| |
add a comment
|
|
up vote
-1
down vote
|
public static double roundToSignificantDigits(double num, int n) {
return Double.parseDouble(new java.util.Formatter().format("%." + (n - 1) + "e", num).toString());
}
This code uses the inbuilt formatting function which is turned to a rounding function
|
本文标签:
Arbitraryroundingnumberdigitssignificant
发表评论