2012-04-28 12 views
7

En primer lugar, no se trata de precisión ni nada por el estilo.Representación del número binario

Mi pregunta es, ¿cómo decide el compilador cómo representar un número?

Tomemos C por ejemplo. Escribo

double d = 4.5632; 

¿Cómo elige su representación binaria? Sé que no está representado exactamente, entonces, ¿cómo elige el número representable más cercano? ¿Se hace en tiempo de compilación? ¿Lo hace la CPU o el sistema operativo?

Por favor, solo responda si sabe cómo sucede esto, las respuestas como "no se preocupe" no son útiles. Además, "depende de la plataforma" tampoco es útil, puedes elegir una plataforma y explicar eso.

+3

Informática no "recoger" la representación binaria - diseñadores de hardware y los autores de compiladores hacen. Eche un vistazo a [este estándar] (http://en.wikipedia.org/wiki/IEEE_754-2008). – dasblinkenlight

Respuesta

6

El compilador no decide (típicamente). La CPU (típicamente) tiene una unidad de coma flotante, que requiere que los valores de coma flotante se representen en un formato particular (típicamente es IEEE-754). Por supuesto, es posible emular una arquitectura completamente diferente, en cuyo caso el autor del compilador/emulador puede elegir libremente una representación completamente diferente. Pero esto no es típico.

En cuanto a cómo la representación léxica específica 4.5632 se convierte a la representación subyacente, eso es especificado por el estándar C. Así que desde la sección 6.4.4.2 de la norma C99 (He destacado la parte más relevante):

parte

La mantisa se interpreta como un (decimal o hexadecimal) número racional; la secuencia de dígitos en la parte exponente es interpretada como un entero decimal. Para las constantes flotantes decimales, el exponente indica la potencia de 10 por la cual la parte significativa es escalar. Para las constantes flotantes hexadecimales, el exponente indica la potencia de 2 por la que se va a escalar la parte significativa. Para constantes decimal flotante, y también para hexadecimal flotante constantes cuando FLT_RADIX no es una potencia de 2, el resultado es o bien el más cercana valor representable, o la mayor o menor valor representable inmediatamente adyacente al valor representable más cercano, elegido de una manera definida por la implementación. Para constantes flotantes hexadecimales cuando FLT_RADIX es una potencia de 2, el resultado es correctamente redondeado.

Esto se realizará en tiempo de compilación (aunque el estándar no lo exige).

+0

Y depende de la norma – nullpotent

+0

Esto no responde mi pregunta: ¿cómo? ¿Cómo sabe que 3.14 debe ser representado por 0100111010 ... o lo que sea? – AMCoder

+0

@AMCoder: he entendido mal tu pregunta. Ver actualización –

0

Sí, esa conversión particular se realiza en tiempo de compilación, ya que double d = 4.5632; es una constante en tiempo de compilación. Lo que está compilado en su código es la representación de este valor en el formato de punto flotante utilizado por la arquitectura de destino. En el caso de la representación IEEE-754 de 32 bits, esto es 0x409205BC. La forma en que la CPU "sabe" que este es un valor algo cercano a 4.5632 depende del estándar de coma flotante en sí. De nuevo, en el caso de IEEE-754 de 32 bits, tenemos un bit para el signo, ocho bits para el exponente y 23 bits para la mantisa.

Cuando se trata de redondear, existen varios métodos que se pueden aplicar. La especificación IEEE-754 menciona cuatro métodos: redondeado a más cercano, redondeado a cero, redondeado a negativo infinito, redondeado a positivo infinito.

0

El compilador genera un programa para ejecutarse en una plataforma. La plataforma podría haber existido antes del compilador, o viceversa. Las representaciones binarias de todo componen el ABI, que es esencialmente una especificación del resultado del compilador. Al final, las cosas se hacen sin importar cómo se hagan, por la razón que sea, pero con suerte hay un ABI para decir exactamente qué sucede.

En la práctica, casi todas las plataformas implementan aritmética de coma flotante según IEEE 754, también conocida como IEC 559. Este estándar internacional bastante antiguo define lo que significan los bits de un punto flotante y cómo debe redondearse la representación decimal del programa a un valor de coma flotante.

Las plataformas sin FPU normalmente aún empaquetarán y descomprimirán los campos de bit de los números IEEE 754 en el software, ya que es probable que aparezcan en forma binaria en los archivos.

Las plataformas con requisitos limitados de interoperabilidad y precisión numérica, como GPU, pueden relajar el estándar de precisión exigido por IEEE 754, pero los rangos numéricos que define son los mejores para una amplia variedad de aplicaciones.

Por supuesto, no puede depender de nada si desea la máxima portabilidad. Pero es una apuesta segura que la conversión de FP decimal a binario (suponiendo que la FPU en sí misma no es decimal) se realiza en tiempo de compilación.

0

Para su ejemplo específico, sí, la representación binaria está codificada en tiempo de compilación. Probablemente llame a una biblioteca C (atod, sscanf, etC) y lo que sea que haga esa biblioteca con truncamiento o redondeo es lo que sucede. Y las "características" o "reglas" de los compiladores para lo que hace no son necesariamente las mismas reglas de tiempo de ejecución que ocurren cuando haces lo mismo. Nunca debe verificar la equivalencia con punto flotante de todos modos, pero si tomara un valor de tiempo de compilación y luego alimente el programa una cadena y convierta ese tiempo de ejecución (digamos que pasa el valor 4.5632 en la línea de comando y utiliza una de las llamadas a la biblioteca) no obtendrás necesariamente el mismo valor de punto flotante. He visto los compiladores (gcc, etc.) hacer un mal trabajo con las constantes de tiempo de compilación, así que como regla, para un número como el suyo (no mucho en la mantisa) mi preferencia por la precisión es hacer esto:

double d; int a; 
a 45632; 
d = a; 
d/=10000; 

E incluso si lo optimiza, tiende a obtener una respuesta mejor y más precisa.

Usted corre el riesgo de error de hardware + OS en la conversión de int a doble, Hauser hizo algunos comentarios sobre los errores de FPU que tienden a estar en el int para flotar y flotar a las operaciones int. Incluso si en tiempo de compilación asumiría que el compilador literalmente haría dos int flotantes luego la división en lugar de hacer una cadena para flotar directamente como tu código.

Han pasado unos años desde que demostré todo esto, tal vez los compiladores han mejorado (es dudoso). Afortunadamente, el hardware ha mejorado (es probable que haya sido muy raro encontrar un fpu sin errores fáciles de encontrar).

+0

El formato de coma flotante IEEE 754 se usa normalmente. Pero depende del hardware si hay una FPU de hardware en su sistema, entonces cualquier formato que use el hardware es probablemente lo que compila el compilador. Si es un fpu blando, entonces es el formato que el soft fpu quiere. IEEE es el formato más difícil/lento/menos confiable debido a la gran cantidad de características. El formato ti dsp, por ejemplo, es significativamente más limpio, más rápido, más confiable, pero no tiene redondeo o infinito o nans. –

0

Su ejemplo particular es convertido por el compilador porque es un literal decimal. Desea detalles, así que vamos a elegir gcc. Hace la conversión en real.c (no sé si esa es la versión actual, pero esa fue la primera copia que encontré a través de Google), en una función llamada real_from_string(). Básicamente hace la conversión con una división larga: en tu caso, 45632/10000.

(decimal a la conversión de punto flotante es un poco complicado, echa un vistazo my blog si desea obtener más información.)

Cuestiones relacionadas