Pregunta

¿Hay alguna forma hábil de redondear a la figura significativa más cercana en PHP?

Asi que:

0->0
9->9
10->10
17->10
77->70
114->100
745->700
1200->1000

?

¿Fue útil?

Solución

$numbers = array(1, 9, 14, 53, 112, 725, 1001, 1200);
foreach($numbers as $number) {
    printf('%d => %d'
            , $number
            , $number - $number % pow(10, floor(log10($number)))
            );
    echo "\n";
}

Desafortunadamente, esto falla horriblemente cuando el número $ es 0, pero produce el resultado esperado para enteros positivos. Y es una solución solo matemática.

Otros consejos

Aquí hay una solución matemática pura. Esta también es una solución más flexible si alguna vez quisiste reunir hacia arriba o hacia abajo, y no solo hacia abajo. Y funciona en 0 :)

if($num === 0) return 0;
$digits = (int)(log10($num));
$num = (pow(10, $digits)) * floor($num/(pow(10, $digits)));

Podrías reemplazar floor con round o ceil. En realidad, si quisiera redondear al más cercano, podría simplificar la tercera línea aún más.

$num = round($num, -$digits);

Si desea tener una solución de Mathy, intente esto:

function floorToFirst($int) {
    if (0 === $int) return 0;

    $nearest = pow(10, floor(log($int, 10)));
    return floor($int / $nearest) * $nearest;
}

Algo como esto:

$str = (string)$value;
echo (int)($str[0] . str_repeat('0', strlen($str) - 1));

Es totalmente no mate, pero solo lo haría utilizando la longitud de la picadura ... probablemente haya una forma más suave de manejarlo, pero podría acomodarlo con

function significant($number){
    $digits = count($number);
    if($digits >= 2){
        $newNumber = substr($number,0,1);
        $digits--;
        for($i = 0; $i < $digits; $i++){
            $newNumber = $newNumber . "0";
        }
    }
    return $newNumber;
}

Una alternativa basada en matemáticas:

$mod = pow(10, intval(round(log10($value) - 0.5))); 
$answer = ((int)($value / $mod)) * $mod;

Sé que este es un hilo viejo, pero lo leí cuando busco inspiración sobre cómo resolver este problema. Esto es lo que se me ocurrió:

class Math
{
    public static function round($number, $numberOfSigFigs = 1)
    {
        // If the number is 0 return 0
        if ($number == 0) {
            return 0;
        }

        // Deal with negative numbers
        if ($number < 0) {
            $number = -$number;
            return -Math::sigFigRound($number, $numberOfSigFigs);
        }

        return Math::sigFigRound($number, $numberOfSigFigs);
    }

    private static function sigFigRound($number, $numberOfSigFigs)
    {
        // Log the number passed
        $log = log10($number);

        // Round $log down to determine the integer part of the log
        $logIntegerPart = floor($log);

        // Subtract the integer part from the log itself to determine the fractional part of the log
        $logFractionalPart = $log - $logIntegerPart;

        // Calculate the value of 10 raised to the power of $logFractionalPart
        $value = pow(10, $logFractionalPart);

        // Round $value to specified number of significant figures
        $value = round($value, $numberOfSigFigs - 1);

        // Return the correct value
        return $value * pow(10, $logIntegerPart); 
    }
}

Si bien las funciones aquí funcionaron, necesitaba dígitos significativos para números muy pequeños (comparando la criptomoneda de bajo valor con Bitcoin).

La respuesta en Número de formato a n dígitos significativos en PHP Trabajó, algo, aunque PHP muestran números muy pequeños en notación científica, lo que hace que algunas personas sean difíciles de leer.

enter image description here

Intenté usar Number_Format, aunque eso necesita un número específico de dígitos después del decimal, que rompió la parte 'significativa' del número (si se ingresa un número de establecimiento) y a veces devuelve 0 (para números más pequeños que el número establecido).

La solución fue modificar la función para identificar números realmente pequeños y luego usar Number_Format en ellos, tomando el número de dígitos de notación científica como el número de dígitos para Number_Format:

function roundRate($rate, $digits)
{
    $mod = pow(10, intval(round(log10($rate))));
    $mod = $mod / pow(10, $digits);
    $answer = ((int)($rate / $mod)) * $mod;
    $small = strstr($answer,"-");
    if($small)
    {
        $answer = number_format($answer,str_replace("-","",$small));
    }
    return $answer;
}

Esta función conserva los dígitos significativos y presenta los números en formato fácil de leer para todos. (Lo sé, no es lo mejor para las personas científicas ni siquiera los números de aspecto 'bonito' de longitud más consistente, pero en general es la mejor solución para lo que necesitábamos).

enter image description here

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top