Acerca de punto fijo y punto flotante
1. Representación de almacenamiento de tipo doble
La representación del tipo de punto flotante de Java está completamente de acuerdo con los estándares IEEE754 (Estándares de números de punto flotante IEEE 754). Puede ir al sitio web de estándares IEEE (www.ieee.org). El contenido de este estándar básicamente describe el formato de almacenamiento (diseño de almacenamiento) de los tipos de punto flotante. A continuación, resumiré algunos párrafos para resumir el estándar. consulte el texto original del estándar.
1. ¿Qué es un número de punto flotante?
Hay dos formas de expresar números reales en las computadoras: representación de punto fijo (fijo). -punto) y representación de punto flotante (punto flotante) La representación de punto fijo está en el punto decimal existente en algún lugar en el medio del número. La representación de la parte entera y la parte decimal no es diferente de. La representación de un número entero ordinario. Por ejemplo, si la longitud de nuestro número es 4 y el punto decimal está en el medio, entonces puede representar 10,28 o 00,01. Las representaciones de punto fijo con propiedades similares a este método también utilizan formas fraccionarias. La forma de ventana de los números de punto fijo hace imposible representar números muy grandes o muy pequeños y cuando se produce la división, se pierde una gran cantidad de precisión.
Los números de punto flotante utilizan la notación científica. Representa números reales. Por ejemplo, 123.456 se puede expresar como 1.23456 × 102. En comparación con las limitaciones de la ventana fija (ventana fija) de los números de punto fijo, utiliza una ventana flotante (ventana deslizante), por lo que puede representar un número real. número con un rango de precisión mayor
2. Diseño de almacenamiento (diseño de almacenamiento)
El llamado diseño de almacenamiento es la forma en que se representa un número de punto flotante en la memoria. Los números de coma flotante incluyen flotante y doble. El primero tiene 4 bytes, que son 32 bits, y el segundo tiene 8 bytes, que son 64 bits. Los diseños son:
Signo exponente parte decimal desplazamiento Adicional (sesgo). )
Precisión simple 1[31] 8[30-23] 23[22-00] 127
Precisión doble 1[63] 11[62-52] 52 [51- 00] 1023
El interior de los corchetes es el rango numérico de los bits y el exterior es el número de bits ocupados por la parte. Al desplazamiento se le añade contenido que no está representado por los bits. y es una constante, que se explicará más adelante.
El signo tiene un solo bit: 0-representa un número positivo 1-representa un número negativo
Parte del exponente: resta el. valor de la parte del exponente (8 bits/11 bits, sin signo) El desplazamiento se agrega para obtener el exponente real del número. Por ejemplo, el valor es 200 y el exponente real es 73=200-127. , the constante sesgo=1023
Mantisa: ¿Qué es la mantisa? Para un científico En términos de conteo, la forma es así L.M×BE, entonces esta L.M es la llamada mantisa. un dígito inicial y una parte decimal. Por ejemplo, 5 se puede expresar de diferentes formas usando notación científica:
5*100
0,5*101
. 50*10-1
Luego introducimos un concepto, forma normalizada (form) y forma desnormalizada (forma desnormalizada). Definimos la forma normalizada como la forma de expresión con el punto decimal ubicado después del primer número que se encuentra. no 0 como forma normalizada, por lo que la primera forma anterior es la forma normalizada y las otras son formas desnormalizadas. La representación de punto flotante en Java sigue completamente este estándar, solo hay dos formas de forma normalizada: 1.f y forma desnormalizada. 0.f
Entonces, para nuestro diseño de bits, elija la base. Si es 2, solo un número es distinto de cero, y ese es 1. Entonces, nuestro implícito.
El número inicial no necesita ocupar un solo dígito, porque aparte de 0, solo puede ser 1. Las reglas implícitas específicas se mostrarán más adelante
3. p>Corresponde a lo anterior En la tabla, el significado del número de coma flotante representado por el rango de valores correspondiente a cada área:
El bit de signo s, el bit de exponente e y el el lugar decimal f representa el significado v
0 00. .00 00..00 0
0 00..00 00..01
: p>
11..11 Número real positivo no canónico, método de cálculo v=0.f × 2(-b 1)
0 00..01
:
11..10 XX..XX Normalización positiva Número real, método de cálculo v=1.f × 2(e-b)
0 11..11 00..00 Infinito positivo
0 11..11 00..01
:
01..11 SNAN no numérico sin sentido
0 11. .11 10..00
:
p>
11..11 QNAN no numérico sin sentido
Donde b=127(flotante)/ b = 1023 (doble), SNAN representa un resultado de operación no válido y QNAN representa un resultado de operación incierto.
Si el bit de signo s se cambia a 1, entonces todos los significados son números negativos. y otros significados son los mismos.
Además, vemos que, para números sin sentido, la parte del exponente es todo 1, lo que significa que hay muchas combinaciones de no números sin sentido en nuestro Java. Es bastante sencillo determinar si un número es NAN
static public boolean isNaN(double v) {
return (v != v
} <; /p>
Se puede ver desde aquí que la máquina virtual tiene Al comparar datos de tipo doble, primero se debe determinar el valor del índice, y solo cuando se descubre que no es todo 1, se realiza bit a bit. Se realiza la comparación de la memoria. Por supuesto, esta es mi suposición, realmente no sé si este es el caso.
Además, ahora sabemos muy bien que el valor mínimo es el tipo doble. puede representar es la distancia entre sus valores, que es lo que llamamos precisión. Cuando los números se acumulan paso a paso hacia números enteros con esta precisión, no puede coincidir exactamente con 1. En otras palabras, 1 no es un múltiplo entero del valor mínimo (. precisión/distancia). Por lo tanto, si configura la variable double d = 0.1; el resultado no será 0.1, porque 0.1 no se puede representar;
2. /p>
Sabemos muy bien que el tipo Double de Java proporciona una función llamada función doubleToLongBits. Esta función es en realidad muy simple. Sabemos que el tipo largo y el tipo doble son todos de 64 bits y sus tamaños de memoria son los mismos. Lo que hace esta función es copiar la estructura de memoria correspondiente al doble a la estructura de memoria de la variable de tipo largo del mismo tamaño. Por lo tanto, Java no admite la configuración de bits en la operación de tipo doble. :
1. Esta función no se puede completar en lenguaje Java, por lo que está implementada por JNI
2. Podemos imprimir la estructura de la memoria usando operaciones de bits en el tipo largo. check
/**
* Prueba
*/
public static void main(String[] args){
p>
miPrueba t = nueva miPrueba();
doble d = 0.1d
largo;
l = Double.doubleToLongBits(d);
System.out.println(t.getLongBits(l));
}
/** p>
/**
p>
* Obtener la representación de bits de la cadena entera constante
* @param a
* @return
*/
public String getLongBits(long a){
//Matriz de bytes de 8 bytes, lectura en voz alta
byte[] b = nuevo byte[8];
p>
for(int i=7;igt;=0;i--){
b[i ] = (byte)(aamp;0x000000FF);
a = agt;
}
return this.byte2hex(b); /Llamar a la siguiente función
}
/**
* Convertir matriz de bytes en cadena
* @param b
* @return
*/
cadena estática pública byte2hex(byte[] b){
StringBuffer sb=new StringBuffer(); /p>
String stmp="";
for(int n=0;nstmp=(Integer.toHexString(b[n]amp;0XFF));
if(stmp.length()==1){
//Agrega ceros al final de menos de dos dígitos
sb.append("0" stmp
} else{
sb.append( stmp);
}
if(n//":" como separador
sb.append(":");
}
}
return sb.toString().toUpperCase(); >
}
El resultado de la memoria impreso por 0.1 es:
3F:B9:99:99:99:99:99:9A
Restauremos y comparemos con la tabla comparativa de significados de la primera sección:
0 01111111011 1001...1010
Si estás interesado, puedes utilizar una calculadora científica para calcular su valor de acuerdo con las reglas de la primera sección. Oh, resulta que pasamos System.out El resultado impreso por println(d).