Desbordamiento de enteros en la suma de múltiplos de 3 y 5

Estoy seguro de que esta pregunta se ha hecho mucho, pero he consultado otros foros y he intentado abordar el problema, lo que no parece ayudar. Estoy pensando que hay un problema de desbordamiento, pero no recuerdo cómo solucionarlo. Tomé un largo descanso de la codificación (mi culpa allí), así que estoy intentando algunos problemas para ayudarme a volver al ritmo de las cosas. Entonces, solo me pregunto qué está yendo mal. cuando intento n = 1000 la respuesta es incorrecta, pero los números más pequeños parecen funcionar bien. Dado que los números grandes no funcionarán, creo que es un desbordamiento de enteros.

def n_number():
    n = raw_input("Enter a max number: ")
    try:
        int(n)
        return n

    except ValueError:
        print 'Value is not an integer'
        exit(1)

# 'function that will add multiples of 3 and 5 that are less than the given value, n.'
def sum_multiplies(n):
    sum = long(0)
    counter3, counter5 = int(1),int(1)

    value3 = 3*counter3
    value5 = 5*counter5

    while True:
        # 'sums of multiples of 5\'s less than n'
        if value5<int(n):
            sum+= value5
            counter5+=1
            value5 = 5*counter5

        # 'sums of multiples of 3\'s less than n'
        if value3<int(n):
            sum+= value3
            counter3+=1
            value3 = 3*counter3

        else:
            break

    print "sum: %s" %sum
    print "counter3: %s" %counter3
    print "counter5: %s" %counter5

def main():
    'max number is in n'
    n = n_number()

    sum_multiplies(n)

if __name__ == "__main__":
    main()

preguntado el 27 de julio de 12 a las 21:07

no puedes desbordar ints en Python, son de precisión arbitraria (módulo el long detalles de implementación en Python 2, y el hecho de que algunas funciones internas locas como range en realidad tirará OverflowErrors ya que solo pueden hacer C doubles). -

No hay problema con el desbordamiento, usa el mod (%) operador para determinar si un número dado es divisible por algún otro. P.ej. n%3 == 0 significa n es divisible por 3 etc.-

Esto se puede hacer mucho más fácil: sum( (x for x in range(1000) if x%3==0 or x%5==0) ) -

@Levon: sí, lo sé, pero luego comienza a ser más difícil de leer para un principiante. -

@zyeek: además, es posible que desee corregir la sangría de su código. Siempre es bueno tener algo que podamos copiar/pegar y jugar. -

5 Respuestas

El problema es que estás contando números que son múltiplos de 3 y 5 (como 15) dos veces.

Una forma de resolverlo sería agregar:

if counter3%5 == 0: continue

para saltarse la doble contabilidad.

Respondido 27 Jul 12, 21:07

ah bien Lo entiendo completamente ahora. No estoy seguro de por qué ni siquiera me molesté en pensar en eso. Gracias - zeek

Actualmente estás haciendo esto en O(n) tiempo - ¡puedes hacerlo en tiempo constante!

' sum values from 1 to m'
def unitSum(m):
    return (m * (m + 1)) / 2

def sum_multiplies(n):
    threes = int(n / 3)
    fives = int(n / 5)
    fifteens = int(n / 15)
    threesum = unitSum(threes) * 3
    fivesum = unitSum(fives) * 5
    fifteensum = unitSum(fifteens) * 15
    return threesum + fivesum - fifteensum

Tendrás que perdonar mi falta de conocimiento de Python, soy un chico de Java. Puede haber algunos errores de sintaxis casuales. Pero la idea aquí es que, para el ejemplo de n = 40, estás sumando 3 5 6 9 10 12 15 18 20 21 24 25 27 30 33 35 36 39 40. Esto es lo mismo que 3 6 9 12 15 18 21 24 27 30 33 36 39 UNION 5 10 15 20 25 30 35 40 Ahora reconociendo que 3 6 9 12 ... es el mismo que 3 * (1 2 3 4...), y lo mismo con los cincos, podemos tomar la "suma unitaria" (1 2 3 4) hasta el número de términos, que es n / mult, y multiplicamos esa suma por el mult, como hacemos con 3 * (1 2 3 4). La buena noticia es que la suma unitaria se puede calcular en tiempo constante, como n * (n + 1) El único inconveniente es que los que son un múltiplo de 15 estarán allí dos veces (contados tanto en los 5 como en los 3), por lo que también tenemos que restarlos.

Respondido 27 Jul 12, 22:07

si, gracias. Simplemente me dio flojera buscar la fórmula para encontrar la fórmula de la suma de un rango dado de valores de 1 a x. Recuerda eso de mi clase de matemáticas concretas. Solo estoy tratando de practicar en mi pitón. Además, gracias por recordarme que siempre busque una mejor manera de hacer las cosas para la optimización. En python, que acabo de leer recientemente, podría hacer esta suma ([i in for i in range (1,1000) if i%3 == 0 o i%5 == 0]), pero soy bastante seguro que esto es un O(n) - zeek

es O(n) - y creo que tengo un pequeño error en ese código, pero la idea está ahí - Córcega

Parece que no tuve un error, aparte de la /2 error que omití antes. Aquí hay una muestra de ello: ideone.com/YQ4M4 - Córcega

Parece que estás contando dos veces los múltiplos de 15.

Respondido 27 Jul 12, 21:07

Debería ser bastante rápido, bastante legible y ejecutarse en CPython 2.x y 3.x. Lo he hecho #! para pypy, pero eso no es por necesidad. Tenga en cuenta que range() está ansioso en 2.x, perezoso en 3.x:

#!/usr/local/pypy-1.9/bin/pypy

divisible_by_3 = set(range(0, 1000, 3))
divisible_by_5 = set(range(0, 1000, 5))

divisible_by_either = divisible_by_3 | divisible_by_5

print(sum(divisible_by_either))

Respondido 27 Jul 12, 22:07

Usando expresiones de generadores, aquí hay una sola línea

result = sum(num for num in xrange(1000) if (num % 5 ==0) or (num % 3 == 0))

Respondido 27 Jul 12, 22:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.