¿Intentará una computadora dividir por cero?

59

Todos sabemos que 0/0es Undefinedy devuelve un error si tuviera que ponerlo en una calculadora, y si tuviera que crear un programa (en C por lo menos) el sistema operativo terminaría cuando trato de dividir por cero.

Pero lo que me he estado preguntando es si la computadora incluso intenta dividir por cero , o simplemente tiene "protección incorporada", de modo que cuando "ve" 0/0devuelve un error incluso antes de intentar calcularlo.

Ankush
fuente
10
0/0 no está definido, cualquier otro número / 0 es un tipo diferente de error, parece confuso los dos
edc65
77
Cualquier número dividido por 0 es indefinido, matemáticamente hablando.
ManoDestra
12
@jwg: "si tuviera un valor sería 1", no necesariamente; hay ramas enteras de las matemáticas dedicadas a lo que el valor podría ser en diferentes circunstancias :)
psmears
11
Para aclarar la terminología aquí, 0/0 se llama una forma indeterminada mientras que x / 0 para x distinto de cero no está definido . Un cálculo que termina con 0/0 a menudo se puede calcular de una manera diferente para dar una respuesta real, mientras que x / 0 carece esencialmente de sentido.
Era
99
@jwg, entonces podrías estar interesado en la regla de l'hopital. Definitivamente, hay casos en los que 0/0 no implica un valor de 1.
d0nut

Respuestas:

74

La CPU ha incorporado la detección. La mayoría de las arquitecturas de los conjuntos de instrucciones especifican que la CPU quedará atrapada en un controlador de excepciones para la división entera entre cero (no creo que le importe si el dividendo es cero).

Es posible que la verificación de un divisor cero ocurra en paralelo en el hardware junto con el intento de hacer la división, sin embargo, la detección de la condición ofensiva cancela efectivamente la división y las trampas, por lo que realmente no podemos saber si alguna parte de que intentó la división o no.

(El hardware a menudo funciona así, haciendo varias cosas en paralelo y luego eligiendo el resultado apropiado porque cada una de las operaciones puede comenzar de inmediato en lugar de serializar la elección de la operación adecuada).

El mismo mecanismo de trampa a excepción también se usará cuando la detección de desbordamiento esté activada, lo que usted solicita usualmente usando diferentes instrucciones de agregar / sub / mul (o una marca en esas instrucciones).

La división de punto flotante también tiene una detección integrada para dividir por cero, pero devuelve un valor diferente ( IEEE 754 especifica NaN ) en lugar de atrapar a un controlador de excepciones.


Hipotéticamente hablando, si la CPU omitió cualquier detección para intentar dividir por cero, los problemas podrían incluir:

  • colgar la CPU (por ejemplo, en un bucle de inf.): esto podría suceder si la CPU usa un algoritmo para dividir que se detiene cuando el numerador es menor que el divisor (en valor absoluto). Un bloqueo como este se consideraría como un bloqueo de la CPU.
  • una respuesta basura (posiblemente predecible), si la CPU usa un contador para terminar la división en el máximo número posible de pasos de división (por ejemplo, 31 o 32 en una máquina de 32 bits).
Erik Eidt
fuente
51
@Ankush Un "bloqueo del sistema" no es realmente algo que sucede a nivel de CPU. El comportamiento más probable de una CPU que no atrapó la división entre cero sería que simplemente realiza la operación de división, produce algunos resultados sin sentido y continúa. Al igual que cuando agrega dos enteros que se desbordan.
Ixrec
66
Para el punto flotante, la elección entre "NaN" y "trampa" generalmente se puede configurar moviendo banderas en la FPU.
Vatine
10
@Ankush En caso de que lo que dijo lxrec no estuviera claro: en lo que respecta a la CPU, no existe un bloqueo.
user253751
77
@Ankush Pocas situaciones causan un "bloqueo del sistema" a nivel de CPU. En esos casos, estamos hablando de cosas como el apagado de protección térmica (protección contra sobrecalentamiento), fallas triples y situaciones similares. Casi todos los bloqueos que encontrará en el uso ordinario, incluidos los códigos de operación no válidos , se manejan atrapando y recuperando de alguna manera, o simplemente ignorando el error y continuando la ejecución en un estado potencialmente impuro, tal vez haya establecido algún indicador de error.
un CVn
8
Si no atrapara la división entre cero, el resultado sería, en lenguaje de programación, "Comportamiento indefinido". Esto significa que la computadora puede hacer cualquier cosa. Puede, como menciona Bergi, entrar en un bucle con errores y colgar. Simplemente puede generar una serie de bits no especificados que resultaron de su implementación de la lógica de división (recuerde, una computadora no se "divide" en el sentido matemático. Realiza una operación en dos números, que está lo suficientemente cerca de la división que normalmente llamamos simplemente "división" (ver también redondeo de coma flotante).
Cort Ammon
34

Depende del idioma, del compilador, de si está usando números enteros o números de coma flotante, etc.

Para el número de coma flotante, la mayoría de las implementaciones usan el estándar IEEE 754 , donde la división por 0 está bien definida. 0/0 da un resultado bien definido de NaN (no un número), y x / 0 para x ≠ 0 da + Infinito o -Infinito, dependiendo del signo de x.

En lenguajes como C, C ++, etc. la división por cero invoca un comportamiento indefinido. Entonces, según la definición del lenguaje, cualquier cosa puede suceder. Especialmente cosas que no quieres que sucedan. Al igual que todo funciona perfectamente bien cuando escribe el código y destruye los datos cuando su cliente lo usa. Entonces, desde el punto de vista del lenguaje, no hagas esto . Algunos idiomas garantizan que su aplicación se bloqueará; depende de ellos cómo se implementa esto. Para esos idiomas, la división por cero se bloqueará.

Muchos procesadores tienen algún tipo de instrucción de "división" incorporada, que se comportará de manera diferente según el procesador. En los procesadores Intel de 32 bits y 64 bits, las instrucciones de "división" bloquean su aplicación cuando intenta dividir por cero. Otros procesadores pueden comportarse de manera diferente.

Si un compilador detecta que ocurrirá una división por cero cuando ejecuta algún código, y el compilador es bueno para sus usuarios, probablemente le dará una advertencia y generará una instrucción de "división" incorporada para que el comportamiento sea el mismo.

gnasher729
fuente
22
"En los procesadores Intel de 32 bits y 64 bits, las instrucciones de" división "bloquearán su aplicación cuando intente dividir por cero". Cita necesaria. Las CPU no tienen idea de las aplicaciones, ejecutan instrucciones y (si incluimos la MMU) imponen límites de acceso a la memoria (a menos que estén en el anillo 0 , o equivalente en arquitecturas que no sean Intel-x86). Que la instrucción sea parte de la Aplicación A en lugar de la Aplicación B o el Componente C del sistema operativo es irrelevante para la CPU; si la instrucción puede ser la Instrucción X o usar la Dirección de memoria Y es relevante.
un CVn
1
Para agregar al comentario de @ MichaelKjörling: El sistema operativo tiene formas de no confirmar la aplicación de este (y otros tipos de errores). En el mundo de Windows, es el EXCEPTION_INT_DIVIDE_BY_ZEROvalor en el EXCEPTION_RECORDque será manejado por el (con suerte) Structed Exception Handling Handler
instalado
1
A veces hacen otras cosas además de garantizar que su aplicación se bloqueará. Por ejemplo, muchos idiomas / plataformas garantizan que lanzarán una excepción en la división por cero. Luego puede atrapar y manejar dicha excepción sin fallar.
reirab
2
Puede eliminar el "mayo" dentro de "Otros procesadores pueden comportarse de manera diferente": en la plataforma PowerPC, la división solo produce un resultado cero en la división por cero. Lo cual es mucho más útil que el comportamiento de pánico de la plataforma X86.
cmaster
13

Parece que te estás preguntando qué pasaría si alguien hiciera una CPU que no compruebe explícitamente cero antes de dividir. Lo que suceda depende completamente de la implementación de la división. Sin entrar en detalles, un tipo de implementación produciría un resultado que tiene todos los bits establecidos, por ejemplo, 65535 en una CPU de 16 bits. Otro podría colgar.

Bingo
fuente
1

Pero lo que me he estado preguntando es si la computadora incluso intenta dividir por cero, o simplemente tiene "protección incorporada", de modo que cuando "ve" 0/0 devuelve un error incluso antes de intentar calcularlo.

Como x/0no tiene sentido, punto, las computadoras siempre deben verificar la división por cero. Aquí hay un problema: los programadores quieren calcular (a+b)/csin tener que molestarse en verificar si ese cálculo tiene sentido. La respuesta subyacente a la división por cero por la CPU + tipo de número + sistema operativo + lenguaje es hacer algo bastante drástico (por ejemplo, bloquear el programa) o hacer algo demasiado benigno (por ejemplo, crear un valor que no sentido como el punto flotante IEEE NaN, un número que es "No es un número").

En un entorno ordinario, se espera que un programador sepa si (a+b)/ctiene sentido. En este contexto, no hay razón para verificar la división por cero. Si ocurre la división por cero, y si el lenguaje de máquina + lenguaje de implementación + tipo de datos + respuesta del sistema operativo a esto es hacer que el programa se bloquee, está bien. Si la respuesta es crear un valor que eventualmente pueda contaminar cada número del programa, también está bien.

Ni "algo drástico" ni "demasiado benigno" es lo correcto en el mundo de la informática de alta confiabilidad. Esas respuestas predeterminadas pueden matar a un paciente, estrellar un avión o hacer explotar una bomba en el lugar equivocado. En un entorno de alta confiabilidad, un programador que escribe (a+b)/cserá asesinado durante la revisión del código, o en los tiempos modernos, tal vez sea asesinado automáticamente por una herramienta que verifica las construcciones verboten. En este entorno, ese programador debería haber escrito algo similar a div(add(a,b),c)(y posiblemente alguna comprobación del estado de error). Debajo del capó, las div(y también las add) funciones / macros protegen contra la división por cero (o desbordamiento en el caso de add). Lo que implica esa protección es muy específico de implementación.

David Hammen
fuente
El hecho de que NaN no obedezca la aritmética que aprendió en la escuela no significa que no tenga sentido. Obedece aritmética diferente
Caleth
-2

Ahora sabemos eso x/0y 0/0no tenemos respuestas bien definidas. ¿Qué sucede si intentas calcular de 0/0todos modos?

En un sistema moderno, el cálculo se pasa a la MPU dentro de la CPU y se marca como una operación ilegal, regresando NaN.

En un sistema mucho más antiguo, como las computadoras hogareñas de los años 80 que no tenían división en chip, el cálculo se realizaba con cualquier software que se estuviera ejecutando. Hay algunas opciones posibles:

  • Reste copias cada vez más pequeñas del divisor hasta que el valor llegue a cero y realice un seguimiento de qué copias de tamaño se restaron
    • Si verifica cero antes de la primera resta, saldrá rápidamente y el resultado será 0
    • Si se supone que debe poder restar al menos una vez, el resultado será 1
  • Calcular los logaritmos de ambos números, restarlos y elevar e a la potencia del resultado. Un método muy ineficiente en comparación con el método de sustracción anterior, pero matemáticamente válido.
    • Es posible que se produzca un desbordamiento al intentar calcular log(0)y el software utilizará sus rutinas de manejo de errores o se bloqueará
    • El software podría suponer que todos los logaritmos se pueden calcular en un número fijo de pasos y devolver un valor grande pero incorrecto. Dado que ambos logaritmos serían iguales, la diferencia sería 0y e 0 = 1, dando un resultado de1

En otras palabras, dependería de la implementación lo que sucedería y sería posible escribir software que produzca resultados correctos y predecibles para cada valor, pero valores aparentemente extraños para 0/0eso son, sin embargo, aún internamente consistentes.

CJ Dennis
fuente
3
Esta pregunta se trata de dividir por cero en los enteros, y no existe tal cosa como NaNen los enteros.
David Hammen
3
Ninguna CPU va a calcular registros y restar para calcular el resultado de la división. El tiempo de instrucción del logaritmo es varios órdenes de magnitud mayor que una división. ¿Cuál es el valor de log (0)?
wallyk
1
@DavidHammen El OP nunca mencionó enteros, y tampoco nadie que haya comentado sobre la pregunta. Los enteros solo se mencionan en las respuestas.
CJ Dennis
@wallyk Ya dije en mi respuesta que los logaritmos son very inefficientpara la división. El costo de la aritmética es (suma = resta) <= multiplicación <= división. Si no tiene una MPU que pueda dividir en el mismo número de ciclos de reloj que la suma (generalmente uno), entonces la división es más costosa que la suma y la resta y, por lo general, también más costosa que la multiplicación.
CJ Dennis