문제

할 수 있는 방법 당신은 라운드 수(다만 정수>0)N 뜻깊은 자리?

예를 들어,내가 원하는 경우 라운드를 세 가지 중요한 자리 숫자,내가 찾는 수식을 취할 수 있:

1,239,451 및 반환 1,240,000

12.1257 및 반환 12.1

.0681 및 반환 .0681

5 고 돌아 5

자연적으로는 알고리즘하지 않아야 하드 코딩을 처리 N 의 3 지만,그 시작이 될 것 이다입니다.

도움이 되었습니까?

해결책

다음은 12.100000000000001 버그없이 Java의 동일한 코드입니다.

또한 반복 코드를 제거하고 변경했습니다 power 플로팅 문제를 방지하기 위해 타입 정수에 n - d 완료되었고, 긴 중간체를 더 명확하게 만들었습니다.

버그는 많은 수를 적은 수로 곱하여 발생했습니다. 대신 비슷한 크기의 두 숫자를 나눕니다.

편집하다
더 많은 버그를 수정했습니다. NAN이 발생할 수 있으므로 0을 추가했습니다. 함수가 실제로 음수로 작동합니다 (원래 코드는 음수 로그가 복소수이기 때문에 음수를 다루지 않습니다).

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;
}

다른 팁

짧고 달콤한 JavaScript 구현은 다음과 같습니다.

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

요약:

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);
}

그래서 당신은를 찾을 필요가 소수점 첫 번째로 자리,저장한 다음 다음 N-1 숫자,그 라운드의 N 번째 자리에 기초합니다.

우리가 사용할 수 있습니다 로그인을 첫 번째입니다.

log 1239451 = 6.09
log 12.1257 = 1.08
log 0.0681  = -1.16

그래서에 대한 숫자>0,취 ceil 의 로그를 보실 수 있습니다.에 대한 숫자 < 0,취할 바닥의 로그를 보실 수 있습니다.

이제 우리는 숫자 d:7 에서 첫번째 경우 2 2-2in the3rd.

우리가하 라운드 (d-N)번째 자리입니다.다음과 같습니다.

double roundedrest = num * pow(10, -(d-N));

pow(1239451, -4) = 123.9451
pow(12.1257, 1)  = 121.257
pow(0.0681, 4)   = 681

그런 다음 표준 라운딩 것:

roundedrest = (int)(roundedrest + 0.5);

고 취소 입니다.

roundednum = pow(roundedrest, -(power))

는 힘이 계산됩니다.


에 대한 정확도:Pyrolistical 의 대답은 실제로 가까워 실제 결과입니다.그러나 참고할 수 있는지를 나타냅 12.1 정확히 어떤 경우에도 빠지지 않았습니다.인쇄할 경우 응답에 다음과 같:

System.out.println(new BigDecimal(n));

답변은:

Pyro's: 12.0999999999999996447286321199499070644378662109375
Mine: 12.10000000000000142108547152020037174224853515625
Printing 12.1 directly: 12.0999999999999996447286321199499070644378662109375

그래서 사용하는 파이로가의 대답이다!

"짧고 달콤한"JavaScript 구현이 아닙니다

Number(n).toPrecision(sig)

예를 들어

alert(Number(12345).toPrecision(3)

?

죄송합니다. 여기서는 멍청하지 않습니다. Claudiu의 "Roundit"기능을 사용하고 JavaScript의 .Teprecision을 사용하면 다른 결과를 얻을 수 있지만 마지막 숫자의 반올림만으로는 나에게만 결과가 나됩니다.

자바 스크립트 :

Number(8.14301).toPrecision(4) == 8.143

.그물

roundit(8.14301,4) == 8.144

Pyrolistical의 (매우 좋은!) 솔루션에는 여전히 문제가 있습니다. Java의 최대 이중 값은 10^308의 순서이며, 최소값은 10^-324의 순서입니다. 따라서 기능을 적용 할 때 문제가 발생할 수 있습니다. roundToSignificantFigures 10의 몇 가지 힘 안에있는 것. Double.MIN_VALUE. 예를 들어, 전화 할 때

roundToSignificantFigures(1.234E-310, 3);

그런 다음 변수입니다 power 값 3- (-309) = 312를 가질 것입니다. 결과적으로 변수 magnitude 될 것입니다 Infinity, 그리고 그것은 그때부터 모든 쓰레기입니다. 다행히도 이것은 극복 할 수없는 문제가 아닙니다. 요인 magnitude 그것은 넘쳐나고 있습니다. 정말로 중요한 것은 제품 num * magnitude, 그리고 그것은 넘치지 않습니다. 이것을 해결하는 한 가지 방법은 요인에 의한 곱셈을 분해하는 것입니다. magintude 두 단계로 :


 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;
}

이 Java 솔루션은 어떻습니까 :

double roundToSignificantFigure(double num, int precision){
 return new BigDecimal(num)
            .round(new MathContext(precision, RoundingMode.HALF_EVEN))
            .doubleValue(); 
}

다음은 ATES 'JavaScript의 수정 된 버전입니다.

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;
 }

이것은 5 년 늦었지만 여전히 같은 문제를 가진 다른 사람들을 위해 공유 할 것입니다. 코드 측면에서 간단하고 계산이 없기 때문에 좋아합니다. 보다 중요한 그림을 표시하는 방법 더 많은 정보를 위해서.

인쇄하고 싶을 때입니다.

public String toSignificantFiguresString(BigDecimal bd, int significantFigures){
    return String.format("%."+significantFigures+"G", bd);
}

변환하려는 경우입니다.

public BigDecimal toSignificantFigures(BigDecimal bd, int significantFigures){
    String s = String.format("%."+significantFigures+"G", bd);
    BigDecimal result = new BigDecimal(s);
    return result;
}

다음은 행동의 예입니다.

BigDecimal bd = toSignificantFigures(BigDecimal.valueOf(0.0681), 2);

손으로하는 방식으로 코딩하는 것만 시도해 보셨습니까?

  1. 숫자를 문자열로 변환하십시오
  2. 문자열의 시작 부분에서 시작하여 카운트 숫자 - 선행 제로는 중요하지 않으며 다른 모든 것이 있습니다.
  3. "Nth"숫자에 도착하면 다음 숫자에서 앞서 나가고 5 개 이상이라면 반올림하십시오.
  4. 모든 후행 숫자를 0으로 교체하십시오.

교정, 2009-10-26

본질적으로, n의 경우 분수 숫자 :

• 숫자에 10을 곱하십시오N
• 0.5를 추가하십시오
• 분수 숫자를 잘라냅니다 (즉, 결과를 정수로 잘라냅니다)
• 10으로 나눕니다N

N의 경우 완전한 (비 분수) 숫자 :

• 숫자를 10으로 나눕니다N
• 0.5를 추가하십시오
• 분수 숫자를 잘라냅니다 (즉, 결과를 정수로 잘라냅니다)
• 10을 곱합니다N

예를 들어 "int"(정수 자르기) 연산자가있는 계산기에서이를 수행 할 수 있습니다.

/**
 * 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);
}

다음은 Visual Basic.net의 Pyrolistical (현재 최고 답변) 코드입니다.

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

자바 스크립트 :

Number( my_number.toPrecision(3) );

그만큼 Number 함수는 양식의 출력을 변경합니다 "8.143e+5" 에게 "814300".

이것은 내가 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

return new BigDecimal(value, new MathContext(significantFigures, RoundingMode.HALF_UP)).doubleValue();

나는 이것을 Go에서 필요로했는데, Go Standard Library의 부족으로 인해 약간 복잡했습니다. math.Round() (Go1.10 이전). 그래서 나도 그것을 채찍질해야했다. 여기에 내 번역이 있습니다 Pyrolistical의 훌륭한 답변:

// TODO: replace in go1.10 with math.Round()
func round(x float64) float64 {
    return float64(int64(x + 0.5))
}

// SignificantDigits rounds a float64 to digits significant digits.
// Translated from Java at https://stackoverflow.com/a/1581007/1068283
func SignificantDigits(x float64, digits int) float64 {
    if x == 0 {
        return 0
    }

    power := digits - int(math.Ceil(math.Log10(math.Abs(x))))
    magnitude := math.Pow(10, float64(power))
    shifted := round(x * magnitude)
    return shifted / magnitude
}
public static double roundToSignificantDigits(double num, int n) {
    return Double.parseDouble(new java.util.Formatter().format("%." + (n - 1) + "e", num).toString());
}

이 코드는 내장 형식 기능을 사용하여 반올림 함수로 전환됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top