significativas redondeo quimica operaciones las importancia fisica ejercicios ejemplos con cifras algorithm rounding significant-digits

algorithm - redondeo - importancia de las cifras significativas



Redondeando a un número arbitrario de dígitos significativos (17)

JavaScript:

Number( my_number.toPrecision(3) );

La función Number cambiará la salida del formulario "8.143e+5" a "814300" .

¿Cómo puede redondear cualquier número (no solo enteros> 0) a N dígitos significativos?

Por ejemplo, si quiero redondear a tres dígitos significativos, estoy buscando una fórmula que podría tomar:

1,239,451 y retorno 1,240,000

12.1257 y return 12.1

.0681 y return .0681

5 y vuelta 5

Naturalmente, el algoritmo no debería estar codificado para manejar solo N de 3, aunque eso sería un comienzo.


¿Has intentado simplemente codificarlo de la manera que lo harías a mano?

  1. Convierte el número a una cadena
  2. Comenzando por el comienzo de la cadena, cuente los dígitos: los ceros a la izquierda no son significativos, todo lo demás lo es.
  3. Cuando llegue al dígito "n", mire hacia adelante en el siguiente dígito y si es 5 o más, redondee hacia arriba.
  4. Reemplaza todos los dígitos finales con ceros.

¿Qué tal esta solución Java?

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


Aquí está el código de Pyrolistical (respuesta actual) en Visual Basic.NET, si alguien lo necesita:

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


Aquí está el mismo código en Java sin el error 12.100000000000001 otras respuestas tienen

También eliminé el código repetido, cambié la power a un entero de tipo para evitar problemas de flotación cuando n - d está hecho, y hice el intermedio largo más claro

El error fue causado al multiplicar un número grande con un número pequeño. En cambio, divido dos números de tamaño similar.

EDITAR
Se corrigieron más errores. Comprobación agregada para 0 ya que daría como resultado NaN. Hizo que la función realmente funcione con números negativos (el código original no maneja números negativos porque un registro de un número negativo es un número complejo)

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


Aquí hay una implementación corta y dulce de 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


Aquí hay una versión modificada del JavaScript de Ates que maneja números negativos.

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


Este es uno que se me ocurrió en 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


Esto llegó 5 años tarde, pero aunque lo compartiré para otros, todavía tengo el mismo problema. Me gusta porque es simple y no hay cálculos en el lado del código. Consulte los métodos integrados para mostrar cifras significativas para obtener más información.

Esto es si solo quieres imprimirlo.

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

Esto es si quieres convertirlo:

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

Aquí hay un ejemplo de esto en acción:

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


La solución de Pyrolistical (¡muy agradable!) Todavía tiene un problema. El valor doble máximo en Java es del orden de 10 ^ 308, mientras que el valor mínimo es del orden de 10 ^ -324. Por lo tanto, puede tener problemas al aplicar la función roundToSignificantFigures a algo que está dentro de unas pocas potencias de diez de Double.MIN_VALUE . Por ejemplo, cuando llamas

roundToSignificantFigures(1.234E-310, 3);

entonces la power variable tendrá el valor 3 - (-309) = 312. En consecuencia, la magnitude la variable se convertirá en Infinity , y todo será basura a partir de ese momento. Afortunadamente, este no es un problema insuperable: solo la magnitude del factor está desbordando. Lo que realmente importa es la num * magnitude del producto num * magnitude , y eso no se desborda. Una forma de resolver esto es dividiendo la multiplicación por el factor magintude en dos pasos:

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


Necesitaba esto en Go, que era un poco complicado debido a la falta de math.Round() de la biblioteca estándar de Go. math.Round() (antes de go1.10). Así que tuve que batir eso también. Aquí está mi traducción de la excelente respuesta de 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://.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 }


No es la implementación de JavaScript "corta y dulce"

Number(n).toPrecision(sig)

p.ej

alert(Number(12345).toPrecision(3)

?

Lo siento, no estoy siendo gracioso aquí, es solo que usar la función "roundit" de Claudiu y .toPrecision en JavaScript me da resultados diferentes, pero solo en el redondeo del último dígito.

JavaScript:

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

.RED

roundit(8.14301,4) == 8.144


RESUMEN:

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

Así que debe encontrar el lugar decimal del primer dígito distinto de cero, luego guarde los siguientes dígitos N-1, luego redondee el dígito N en función del resto.

Podemos usar log para hacer lo primero.

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

Entonces, para números> 0, tome el techo del registro. Para números <0, tome la palabra del registro.

Ahora tenemos el dígito d : 7 en el primer caso, 2 en el 2 °, -2 en el 3 °.

Tenemos que redondear el (dN) décimo dígito. Algo como:

double roundedrest = num * pow(10, -(d-N)); pow(1239451, -4) = 123.9451 pow(12.1257, 1) = 121.257 pow(0.0681, 4) = 681

Luego haga lo de redondeo estándar:

roundedrest = (int)(roundedrest + 0.5);

Y deshacer el pow.

roundednum = pow(roundedrest, -(power))

Donde el poder es el poder calculado arriba.

Acerca de la precisión: la respuesta de Pyrolistical es más cercana al resultado real. Pero tenga en cuenta que no puede representar 12.1 exactamente en cualquier caso. Si imprime las respuestas de la siguiente manera:

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

Las respuestas son:

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

Entonces, ¡usa la respuesta de Pyro!


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


[Corregido, 2009-10-26]

Esencialmente, para N dígitos fraccionarios significativos:

• Multiplica el número por 10 N
• Agregar 0.5
• Truncar los dígitos de fracción (es decir, truncar el resultado en un entero)
• Divide por 10 N

Para N dígitos significativos (no fraccionarios) significativos:

• Divida el número por 10 N
• Agregar 0.5
• Truncar los dígitos de fracción (es decir, truncar el resultado en un entero)
• Multiplicar por 10 N

Puede hacer esto en cualquier calculadora, por ejemplo, que tenga un operador "INT" (truncamiento entero).


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


public static double roundToSignificantDigits(double num, int n) { return Double.parseDouble(new java.util.Formatter().format("%." + (n - 1) + "e", num).toString()); }

Este código usa la función de formateo incorporada que se convierte en una función de redondeo