Pregunta

Entonces, procedimiento simple, calcule un número factorial. El código es el siguiente.

int calcFactorial(int num)
{
    int total = 1;

    if (num == 0)
    {
        return 0;
    }

    for (num; num > 0; num--)
    {
        total *= num;
    }

    return total;
}

Ahora, esto funciona bien y elegante (ciertamente hay soluciones más rápidas y elegantes, pero esto funciona para mí) para la mayoría de los números. Sin embargo, al ingresar números más grandes, como 250, para decirlo sin rodeos, se arruina. Ahora, el primer par factorial '' bits '' para 250 son {250, 62250, 15126750, 15438000, 3813186000} como referencia.

Mi código escupe {250, 62250, 15126750, 15438000, -481781296 } que obviamente está desactivado. Mi primera sospecha fue quizás que había violado el límite de un número entero de 32 bits, pero dado que 2 ^ 32 es 4294967296, no lo creo. Lo único en lo que puedo pensar es quizás que infringe un límite de 32 bits firmado , pero ¿no debería ser capaz de pensar en este tipo de cosas? Si el problema es firmar, puedo resolver esto haciendo que el entero no esté firmado, pero esto solo sería una solución temporal, ya que la siguiente iteración produce 938043756000, que está muy por encima del límite 4294967296.

Entonces, ¿mi problema es el límite firmado? Si es así, ¿qué puedo hacer para calcular números grandes (aunque tengo una clase '' LargeInteger '' que hice hace un tiempo que puede ser adecuada!) Sin volver a encontrar este problema?

¿Fue útil?

Solución

2 ^ 32 no te da el límite para enteros con signo.

El límite entero firmado es en realidad 2147483647 (si está desarrollando en Windows usando las herramientas de MS, otras herramientas / plataformas tendrían sus propios límites que probablemente sean similares).

Necesitará una biblioteca de números grandes de C ++ como esta .

Otros consejos

Además de los otros comentarios, me gustaría señalar dos errores graves en su código.

  • No tienes protección contra los números negativos.
  • El factorial de cero es uno, no cero.

Sí, llegaste al límite. Un int en C ++ es, por definición, firmado. Y, eh, no, C ++ no piensa, nunca. Si le dice que haga algo, lo hará, incluso si obviamente es incorrecto.

Considere usar una biblioteca de números grandes. Hay muchos de ellos para C ++.

Si no especifica firmado o no firmado, el valor predeterminado es firmado. Puede modificar esto usando un interruptor de línea de comando en su compilador.

Solo recuerda, C (o C ++) es un lenguaje de muy bajo nivel y hace precisamente lo que le dices que haga . Si le dice que almacene este valor en un int firmado, eso es lo que hará. Usted como programador tiene que descubrir cuándo es un problema. No es el trabajo del idioma.

Mi calculadora de Windows ( Start-Run-Calc ) me dice que

hex (3813186000) =         E34899D0
hex (-481781296) = FFFFFFFFE34899D0

Entonces sí, la causa es el límite firmado. Como los factoriales pueden, por definición, solo ser positivos y solo pueden calcularse para números positivos, tanto el argumento como el valor de retorno deben ser números sin signo de todos modos. (Sé que todo el mundo usa int i = 0 en bucles, yo también. Pero, aparte de eso, deberíamos usar variables siempre sin signo si el valor no puede ser negativo, es una buena práctica IMO).

El problema general con los factoriales es que pueden generar fácilmente muy números grandes. Podría usar un flotador, sacrificando así la precisión pero evitando el problema de desbordamiento de enteros.

Oh, espera, de acuerdo con lo que escribí anteriormente, deberías hacer que sea un flotador sin signo ;-)

Tiene un problema de desbordamiento. Los factoriales pueden exceder fácilmente los límites de los enteros. Podría cambiar su función para devolver dobles, pero eso solo le dará un poco más de espacio. En las aplicaciones, a menudo necesita multiplicar factoriales por números muy pequeños donde el resultado final cabe dentro de un doble pero los pasos intermedios no. Aquí hay un artículo que explica cómo manejar esta situación: http://www.johndcook.com/blog/2008/04/24/how-to-calculate-binomial-probabilities/

Si no recuerdo mal:

unsigned short int = max 65535

unsigned int = max 4294967295

unsigned long = max 4294967295

unsigned long long (Int64) = max 18446744073709551615

Fuente editada:

Valores Int / Long Max

Variable del compilador moderno

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