Lo sé, la pregunta parece ser extraña. Los programadores a veces piensan demasiado. Por favor sigue leyendo ...
En CI uso signed
y unsigned
enteros mucho. Me gusta el hecho de que el compilador me advierte si hago cosas como asignar un entero con signo a una variable sin signo. Recibo advertencias si comparo enteros firmados con enteros sin signo y mucho más.
Me gustan estas advertencias. Me ayudan a mantener mi código correcto.
¿Por qué no tenemos el mismo lujo para las carrozas? Una raíz cuadrada definitivamente nunca devolverá un número negativo. También hay otros lugares donde un valor flotante negativo no tiene sentido. Candidato perfecto para una carroza sin firmar.
Por cierto, no estoy realmente interesado en el solo bit extra de precisión que podría obtener al eliminar el bit de signo de los flotadores. Estoy súper feliz con float
s como lo están ahora. Solo me gustaría marcar un flotador como sin firmar veces y obtener el mismo tipo de advertencias que obtengo con los enteros.
No conozco ningún lenguaje de programación que admita números de punto flotante sin signo.
¿Alguna idea de por qué no existen?
EDITAR:
Sé que la FPU x87 no tiene instrucciones para lidiar con flotadores sin firmar. Solo usemos las instrucciones de flotación firmadas. El mal uso (por ejemplo, ir por debajo de cero) podría considerarse un comportamiento indefinido de la misma manera que el desbordamiento de enteros con signo no está definido.
Respuestas:
La razón por la cual C ++ no tiene soporte para flotantes sin firmar es porque no hay operaciones de código de máquina equivalentes para que la CPU las ejecute. Por lo tanto, sería muy ineficiente apoyarlo.
Si C ++ lo admitiera, a veces estaría utilizando un flotador sin signo y sin darse cuenta de que su rendimiento acaba de ser eliminado. Si C ++ lo admitiera, entonces todas las operaciones de punto flotante tendrían que verificarse para ver si está firmado o no. Y para los programas que realizan millones de operaciones de coma flotante, esto no es aceptable.
Entonces, la pregunta sería por qué los implementadores de hardware no lo admiten. Y creo que la respuesta a eso es que no había un estándar flotante sin signo definido originalmente. Dado que a los idiomas les gusta ser compatibles con versiones anteriores, incluso si se agregaran idiomas, no podrían usarlo. Para ver las especificaciones de coma flotante, debe mirar el estándar 754 de coma flotante IEEE .
Sin embargo, puede evitar tener un tipo de coma flotante sin signo creando una clase flotante sin signo que encapsule un flotante o doble y arroje advertencias si intenta pasar un número negativo. Esto es menos eficiente, pero probablemente si no los está usando intensamente, no le importará esa ligera pérdida de rendimiento.
Definitivamente veo la utilidad de tener un flotador sin firmar. Pero C / C ++ tiende a elegir la eficiencia que funciona mejor para todos sobre la seguridad.
fuente
int
's, toda la verificación de tipos relacionada con signos puede ocurrir en tiempo de compilación. OP sugiere queunsigned float
se implementaría regularmentefloat
con comprobaciones en tiempo de compilación para garantizar que ciertas operaciones sin sentido nunca se realicen. El código y el rendimiento de la máquina resultante podrían ser idénticos, independientemente de si sus flotadores están firmados o no.Hay una diferencia significativa entre enteros con y sin signo en C / C ++:
los valores con signo dejan el bit superior sin cambios (extensión de signo), los valores sin signo borran el bit superior.
La razón por la que no hay flotante sin signo es que rápidamente se encuentra con todo tipo de problemas si no hay valores negativos. Considera esto:
¿Qué valor tiene c? -8. Pero, ¿qué significaría eso en un sistema sin números negativos? FLOAT_MAX - 8 tal vez? En realidad, eso no funciona ya que FLOAT_MAX - 8 es FLOAT_MAX debido a los efectos de precisión, por lo que las cosas son aún más complicadas. ¿Qué pasaría si fuera parte de una expresión más compleja?
Esto no es un problema para los enteros debido a la naturaleza del sistema de complemento de 2.
También considere las funciones matemáticas estándar: sin, cos y tan solo funcionarían para la mitad de sus valores de entrada, no podría encontrar el registro de valores <1, no podría resolver ecuaciones cuadráticas: x = (-b +/- root ( bb - 4.ac)) / 2.a, y así sucesivamente. De hecho, probablemente no funcionaría para ninguna función compleja, ya que tienden a implementarse como aproximaciones polinómicas que usarían valores negativos en alguna parte.
Entonces, los flotadores sin firmar son bastante inútiles.
Pero eso no quiere decir que una clase que verifica el rango de valores flotantes no sea útil, es posible que desee sujetar los valores a un rango dado, por ejemplo, cálculos RGB.
fuente
2's complement
, no habrá problema con tener flotadores sin signo?value >> shift for signed values leave the top bit unchanged (sign extend)
¿Estás seguro de eso? Pensé que era un comportamiento definido por la implementación, al menos para los valores con signo negativo.0.0
, o posiblemente Inf o NaN. O simplemente sea Comportamiento indefinido, como el OP sugerido en una edición de la pregunta. Re: funciones trigonométricas: así que no defina versiones de entrada sin signo desin
y así sucesivamente, y asegúrese de tratar su valor de retorno como firmado. La pregunta no era proponer reemplazar flotante por flotante sin signo, solo agregarunsigned float
como un nuevo tipo.(Como comentario aparte, Perl 6 te permite escribir
y luego puede usarlo
Nonnegative::Float
como lo haría con cualquier otro tipo).No hay soporte de hardware para operaciones de coma flotante sin firmar, por lo que C no lo ofrece. C está diseñado principalmente para ser un "ensamblaje portátil", es decir, lo más cerca posible del metal sin estar atado a una plataforma específica.
[editar]
C es como un ensamblaje: lo que ves es exactamente lo que obtienes. Un implícito "Comprobaré que este flotador no sea negativo para usted" va en contra de su filosofía de diseño. Si realmente lo desea, puede agregar
assert(x >= 0)
o similar, pero debe hacerlo explícitamente.fuente
of ...
no analiza.Creo que el int sin firmar se creó debido a la necesidad de un margen de valor mayor que el que se puede ofrecer.
Un flotador tiene un margen mucho mayor, por lo que nunca hubo una necesidad 'física' de un flotador sin signo. Y como usted mismo señala en su pregunta, la precisión adicional de 1 bit no es para nada.
Editar: Después de leer la respuesta de Brian R. Bondy , tengo que modificar mi respuesta: Definitivamente tiene razón en que las CPU subyacentes no tenían operaciones flotantes sin firmar. Sin embargo, mantengo mi creencia de que esta fue una decisión de diseño basada en las razones que dije anteriormente ;-)
fuente
Creo que Treb está en el camino correcto. Es más importante para los enteros que tenga un tipo correspondiente sin signo. Esos son los que se usan en el desplazamiento de bits y en los mapas de bits. . Un poco de señal se interpone en el camino. Por ejemplo, al desplazar hacia la derecha un valor negativo, el valor resultante es la implementación definida en C ++. Hacer eso con un entero sin signo o desbordamiento de ese tipo tiene una semántica perfectamente definida porque no hay tal cosa en el camino.
Entonces, al menos para los enteros, la necesidad de un tipo separado sin signo es más fuerte que solo dar advertencias. No es necesario tener en cuenta todos los puntos anteriores para las carrozas. Por lo tanto, creo que no hay una necesidad real de soporte de hardware para ellos, y C ya no los admitirá en ese momento.
fuente
C99 admite números complejos y un tipo genérico de sqrt, por
sqrt( 1.0 * I)
lo que será negativo.Los comentaristas destacaron un ligero brillo anterior, ya que me refería a la
sqrt
macro genérica de tipo en lugar de a la función, y devolverá un valor de punto flotante escalar por truncamiento del complejo a su componente real:También contiene un pedo cerebral, ya que la parte real del sqrt de cualquier número complejo es positiva o cero, y sqrt (1.0 * I) es sqrt (0.5) + sqrt (0.5) * I no -1.0.
fuente
sqrt(-0.0)
menudo produce-0.0
. Por supuesto, -0.0 no es un valor negativo .Supongo que depende de que las especificaciones de punto flotante IEEE solo estén firmadas y que la mayoría de los lenguajes de programación las usen.
Artículo de Wikipedia sobre números de punto flotante IEEE-754
Editar: Además, como han señalado otros, la mayoría del hardware no admite flotadores no negativos, por lo que el tipo normal de flotadores es más eficiente ya que existe soporte de hardware.
fuente
Creo que la razón principal es que los flotadores sin signo tendrían usos realmente limitados en comparación con las entradas sin signo. No creo que sea porque el hardware no lo admite. Los procesadores más antiguos no tenían capacidades de coma flotante, todo se emulaba en software. Si los flotadores no firmados fueran útiles, se habrían implementado primero en software y el hardware habría seguido su ejemplo.
fuente
Los tipos enteros sin signo en C se definen de tal manera que obedecen las reglas de un anillo algebraico abstracto. Por ejemplo, para cualquier valor X e Y, agregar XY a Y producirá X. Se garantiza que los tipos enteros sin signo obedecerán estas reglas en todos los casos que no impliquen conversión hacia o desde cualquier otro tipo numérico [o tipos sin signo de diferentes tamaños] , y esa garantía es una de las características más importantes de estos tipos. En algunos casos, vale la pena renunciar a la capacidad de representar números negativos a cambio de las garantías adicionales que solo los tipos sin firmar pueden proporcionar. Los tipos de punto flotante, firmados o no, no pueden cumplir con todas las reglas de un anillo algebraico [por ejemplo, no pueden garantizar que X + YY sea igual a X], y de hecho IEEE no ' incluso les permite cumplir con las reglas de una clase de equivalencia [al exigir que ciertos valores se comparen desiguales entre sí]. No creo que un tipo de punto flotante "sin signo" pueda acatar ningún axioma que un tipo de punto flotante común no podría, así que no estoy seguro de las ventajas que ofrecería.
fuente
IHMO se debe a que soportar los tipos de punto flotante con y sin signo en hardware o software sería demasiado problemático
Para los tipos enteros, podemos utilizar la misma unidad lógica tanto para operaciones enteras con signo como sin signo en la mayoría de las situaciones utilizando la propiedad agradable del complemento de 2, porque el resultado es idéntico en esos casos para las operaciones add, sub, non-widening mul y la mayoría de las operaciones bit a bit. Para las operaciones que diferencian entre versiones firmadas y no firmadas, aún podemos compartir la mayoría de la lógica . Por ejemplo
INT_MIN
. También teóricamente posible, probablemente no se usa en hardware, pero es útil en sistemas que admiten solo un tipo de comparación (como 8080 u 8051)Los sistemas que usan el complemento 1 también solo necesitan una pequeña modificación a la lógica porque es simplemente el bit de transporte envuelto al bit menos significativo. No estoy seguro acerca de los sistemas de magnitud de signos, pero parece que usan el complemento de 1 internamente, por lo que se aplica lo mismo
Desafortunadamente , no tenemos ese lujo para los tipos de punto flotante. Simplemente liberando el bit de signo tendremos la versión sin firmar. Pero entonces, ¿para qué deberíamos usar ese bit?
Pero ambas opciones necesitan un sumador más grande para acomodar el rango de valores más amplio. Eso aumenta la complejidad de la lógica, mientras que la parte superior del sumador se encuentra allí sin usar la mayor parte del tiempo. Se necesitarán aún más circuitos para multiplicaciones, divisiones u otras operaciones complejas.
En los sistemas que utilizan software de punto flotante, necesita 2 versiones para cada función que no se esperaba durante el tiempo que la memoria era demasiado costosa, o tendría que encontrar una forma "complicada" de compartir partes de las funciones firmadas y sin firmar.
Sin embargo , el hardware de punto flotante existía mucho antes de que se inventara C. , por lo que creo que la elección en C se debió a la falta de soporte de hardware debido a la razón que mencioné anteriormente
Dicho esto, existen varios formatos especializados de punto flotante sin signo, principalmente para fines de procesamiento de imágenes, como el tipo de punto flotante de 10 y 11 bits del grupo Khronos
fuente
Sospecho que se debe a que los procesadores subyacentes a los que se dirigen los compiladores de C no tienen una buena manera de tratar con números de coma flotante sin signo.
fuente
Buena pregunta.
Si, como usted dice, es solo para advertencias en tiempo de compilación y ningún cambio en su comportamiento, de lo contrario, el hardware subyacente no se ve afectado y, como tal, solo sería un cambio de C ++ / Compilador.
Me he preguntado lo mismo anteriormente, pero la cosa es: no ayudaría mucho. En el mejor de los casos, el compilador puede encontrar asignaciones estáticas.
O minimalistamente más largo
Pero eso es todo. Con los tipos enteros sin signo también obtienes un entorno definido, es decir, se comporta como aritmética modular.
después de esto 'uc' tiene el valor de 255.
Ahora, ¿qué haría un compilador con el mismo escenario dado un tipo flotante sin signo? Si los valores no se conocen en el momento de la compilación, necesitaría generar un código que primero ejecute los cálculos y luego realice una verificación de signos. Pero, ¿qué sucede cuando el resultado de tal cálculo sería "-5.5", qué valor debería almacenarse en un flotante declarado sin signo? Uno podría probar la aritmética modular como para los tipos integrales, pero eso viene con sus propios problemas: el valor más grande es indiscutiblemente infinito ... eso no funciona, no puede tener "infinito - 1". Ir por el mayor valor distintivo que puede contener tampoco funcionará realmente, ya que allí se encuentra con la precisión. "NaN" sería un candidato.
Por último, esto no sería un problema con los números de punto fijo ya que el módulo está bien definido.
fuente