valor doble mínimo en C / C ++


92

¿Existe una forma estándar y / o portátil de representar el valor negativo más pequeño (por ejemplo, para usar infinito negativo) en un programa C (++)?

DBL_MIN en float.h es el número positivo más pequeño .


4
Iré por -DBL_MAX, pero estoy seguro de que hay alguna razón técnica por la que esto no es así :-)

4
@Neil, no, no lo hay, no es como 2 enteros de complemento
fortran

Todavía no he visto nada en el estándar que diga que el rango de los tipos de punto flotante tiene que ser simétrico alrededor de cero. Pero las constantes en limits.hy <limits> sugieren que tanto el estándar C como C ++ esperan que así sea.
Steve Jessop

4
En realidad, DBL_MIN en float.h es el número normalizado positivo más pequeño . Hay números que son aún menores.
fdermishin

1
@fortran: IEEE 754 FP usa un bit de signo, y ciertamente la mayoría del hardware FP en estos días es IEEE 754. Pero C y C ++ son compatibles con hardware que no es IEEE 754 FP, por lo que la pregunta está abierta sobre si el lenguaje garantiza que -DBL_MAX debe ser igual al valor mínimo representable.
j_random_hacker

Respuestas:


135

-DBL_MAX en ANSI C , que se define en float.h.


esto parece el más estándar y portátil
Will

Aquí está la explicación de mi -1: ¿quién o qué dice que -DBL_MAX está garantizado por el lenguaje C o C ++ como representable, y mucho menos el valor mínimo representable? El hecho de que la mayoría del hardware FP sea compatible con IEEE 754 y utilice esta representación, no significa que -DBL_MAX esté garantizado para funcionar en cualquier plataforma C conforme con el estándar.
j_random_hacker

@j_random_hacker: vea la respuesta de fortran 'a continuación'.
JohnTortugo

3
@j_random_hacker Ese es un muy buen punto, pero el estándar C requiere -DBL_MAXser exactamente representable, por lo que si el hardware FP no es capaz de eso, la implementación simplemente tiene que solucionarlo. Consulte el modelo de punto flotante en 5.2.4.2.2 Características de los tipos flotantes <float.h> p2 de C99 (puede que se haya movido a otro lugar desde entonces).

2
@j_random_hacker Sí, pero p2 especifica que e_min y e_max son independientes del bit de signo, por lo que DBL_MAXes exactamente (1 - b ^ −p) b ^ e_max, que es exactamente representable, el valor finito más negativo es exactamente - (1 - b ^ −p) b ^ e_max, y dado que resulta ser exactamente -DBL_MAX, la negación DBL_MAXtampoco puede introducir errores de redondeo.

70

Los números de coma flotante (IEEE 754) son simétricos, por lo que si puede representar el mayor valor ( DBL_MAXo numeric_limits<double>::max()), simplemente anteponga un signo menos.

Y luego está la forma genial:

double f;
(*((long long*)&f))= ~(1LL<<52);

6
+1 Por señalar la simetría de números de punto flotante :)
Andrew Hare

4
¿Qué pasa con las implementaciones de C / C ++ que no utilizan flotantes IEEE 754?
Steve Jessop

1
El manual de gcc para -ffast-math dice "Establece -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans y -fcx-limited- rango Esta opción no está activada por ninguna opción -O ya que puede dar como resultado una salida incorrecta para programas que dependen de una implementación exacta de las reglas / especificaciones IEEE o ISO para funciones matemáticas. Sin embargo, puede producir un código más rápido para programas que no requieren las garantías de estas especificaciones ". La matemática rápida es una configuración común, y Intel ICC, por ejemplo, la usa por defecto. En general, no estoy seguro de lo que esto significa para mí :-)
Will

4
Significa que las implementaciones no usan la aritmética IEEE 754, pero para ser justos, esas opciones aún usan la representación IEEE. Es posible que encuentre algunas bibliotecas de emulación que utilicen una representación que no sea IEEE, ya que no todos los procesadores tienen un formato flotante nativo (aunque pueden publicar una ABI C que incluye un formato, correspondiente a las bibliotecas de emulación proporcionadas por el fabricante). Por tanto, no todos los compiladores pueden utilizar uno. Depende de lo que quieras decir cuando pides "estándar y / o portátil", hay portátil en principio y portátil en la práctica.
Steve Jessop

3
Lo que dice es cierto para IEEE 754, pero el estándar no requiere el uso de esta codificación (como señala @SteveJessop, portátil en la práctica no es lo mismo que portátil en principio).
Christophe

44

En C, use

#include <float.h>

const double lowest_double = -DBL_MAX;

En C ++ pre-11, use

#include <limits>

const double lowest_double = -std::numeric_limits<double>::max();

En C ++ 11 y posteriores, use

#include <limits>

constexpr double lowest_double = std::numeric_limits<double>::lowest();

¿No estaba min()disponible la función antes de C ++ 11? ¿O es un valor diferente al -max()? en.cppreference.com/w/cpp/types/numeric_limits
Alexis Wilke

5
@Alexis: si observa las tres filas inferiores de la tabla en la página que vinculó, verá que minobtiene el valor positivo más pequeño en magnitud y lowestel valor negativo más grande en magnitud. Sí, es terrible. Bienvenido al brillante mundo de la biblioteca estándar de C ++ :-P.
rubenvb

para C se define en float.h. limits.hes para enteros
Ciprian Tomoiagă

33

Prueba esto:

-1 * numeric_limits<double>::max()

Referencia: numeric_limits

Esta clase está especializada para cada uno de los tipos fundamentales, y sus miembros regresan o establecen los diferentes valores que definen las propiedades que tiene ese tipo en la plataforma específica en la que compila.


1
¿Por qué no solo -numeric_limits<double>::max()?
k06a

4
@ k06a, que tiene la negación representada por un solo carácter en una expresión tan larga, donde la cadena incluso dice "max", seguramente atraerá a alguien tarde o temprano. Se almacena en una variable descriptiva o se usa -1 * ...para aclarar un poco más.
Filip Haglund

20

¿Está buscando el infinito real o el valor finito mínimo? Si es el primero, use

-numeric_limits<double>::infinity()

que solo funciona si

numeric_limits<double>::has_infinity

De lo contrario, debe usar

numeric_limits<double>::lowest()

que se introdujo en C ++ 11.

Si lowest()no está disponible, puede recurrir a

-numeric_limits<double>::max()

que puede diferir de lowest()en principio, pero normalmente no lo hace en la práctica.


+1 para la diferencia entre valor finito e infinito. Pero el estándar no garantiza una codificación de punto flotante simétrico. Entonces, -numeric_limits<double>::max()incluso si funciona en la práctica, no es completamente portátil en teoría.
Christophe

@Christophe: [x] arreglado
Christoph

10

Una solución C ++ verdaderamente portátil

A partir de C ++ 11 puedes usar numeric_limits<double>::lowest(). Según el estándar, devuelve exactamente lo que está buscando:

Un valor finito x tal que no hay otro valor finito y donde y < x.
Significativo para todas las especializaciones en las que is_bounded != false.

Demostración online


¡Muchas respuestas de C ++ no portátiles aquí!

Hay muchas respuestas disponibles -std::numeric_limits<double>::max().

Afortunadamente, funcionarán bien en la mayoría de los casos. Los esquemas de codificación de coma flotante descomponen un número en una mantisa y un exponente y la mayoría de ellos (por ejemplo, el popular IEEE-754 ) utilizan un bit de signo distinto, que no pertenece a la mantisa. Esto permite transformar el positivo más grande en el negativo más pequeño simplemente volteando el signo:

ingrese la descripción de la imagen aquí

¿Por qué no son portátiles?

El estándar no impone ningún estándar de punto flotante.

Estoy de acuerdo en que mi argumento es un poco teórico, pero supongamos que algún compilador excéntrico usaría un esquema de codificación revolucionario con una mantisa codificada en algunas variaciones del complemento a dos . La codificación del complemento a dos no es simétrica. por ejemplo, para un carácter de 8 bits con signo, el máximo positivo es 127, pero el mínimo negativo es -128. Entonces, podríamos imaginar que alguna codificación de punto flotante muestra un comportamiento asimétrico similar.

No conozco ningún esquema de codificación como ese, pero el punto es que el estándar no garantiza que el cambio de signo produzca el resultado deseado . Así que esta respuesta popular (¡lo siento chicos!) No puede considerarse como una solución estándar totalmente portátil. / * al menos no si no afirmas que numeric_limits<double>::is_iec559es cierto * /



1

La pregunta original se refiere al infinito. Entonces, ¿por qué no usar

#define Infinity  ((double)(42 / 0.0))

según la definición de IEEE? Puedes negar eso, por supuesto.


Buena idea ! Y funciona . Pero solo sinumeric_limits<double>::has_infinity && ! numeric_limits<double>::traps
Christophe

1

¿Existe una forma estándar y / o portátil de representar el valor negativo más pequeño (por ejemplo, para usar infinito negativo) en un programa C (++)?

Enfoque C.

Muchas implementaciones admiten +/- infinitos, por lo que el doublevalor más negativo es -INFINITY.

#include <math.h>
double most_negative = -INFINITY;

¿Existe una forma estándar y / o portátil ....?

Ahora también debemos considerar otros casos:

  • Sin infinitos

Simplemente -DBL_MAX.

  • Solo un infinito sin firmar .

Esperaría que en este caso, OP preferiría -DBL_MAX.

  • Valores anormales mayores en magnitud que DBL_MAX.

Este es un caso inusual, probablemente fuera de la preocupación de OP. Cuando doublese codifica como un par de puntos flotantes para lograr el rango / precesión deseado, (ver doble-doble ) existe un máximo normal double y quizás uno mayor de lo normal . He visto debatir si DBL_MAXdebería referirse a la mayor normalidad , a la mayor de ambas.

Afortunadamente, este enfoque emparejado generalmente incluye un infinito, por lo que permanece el valor más negativo -INFINITY.


Para una mayor portabilidad, el código puede seguir el camino

// HUGE_VAL is designed to be infinity or DBL_MAX (when infinites are not implemented)
// .. yet is problematic with unsigned infinity.
double most_negative1 = -HUGE_VAL;  

// Fairly portable, unless system does not understand "INF"
double most_negative2 = strtod("-INF", (char **) NULL);

// Pragmatic
double most_negative3 = strtod("-1.0e999999999", (char **) NULL);

// Somewhat time-consuming
double most_negative4 = pow(-DBL_MAX, 0xFFFF /* odd value */);

// My suggestion
double most_negative5 = (-DBL_MAX)*DBL_MAX;

-1

Si no tiene habilitadas las excepciones flotantes (que no debería en mi humilde opinión), simplemente puede decir:

double neg_inf = -1/0.0;

Esto produce infinito negativo. Si necesita un flotador, puede lanzar el resultado

float neg_inf = (float)-1/0.0;

o utilizar aritmética de precisión simple

float neg_inf = -1.0f/0.0f;

El resultado es siempre el mismo, hay exactamente una representación de infinito negativo tanto en precisión simple como doble, y se convierten entre sí como era de esperar.


¿Por qué harías esto en lugar de simplemente escribir-INFINITY
MM

Además, el infinito puede existir o no, y si existe, es posible que lo positivo y lo negativo no se distingan (en el Estándar C).
MM

En muchos compiladores y / o arquitecturas, su código C / C ++ ralentizará la propagación de valores infinitos y NaN.
markgalassi

@markgalassi Por favor, mire más de cerca: notará que neg_infse inicializa a un valor constante . El compilador se encargará de calcular el infvalor. Y cuando lo usa como valor nulo para calcular un máximo, la primera iteración generalmente lo sobrescribirá con un valor mayor. Es decir, el rendimiento no es un problema. Y el OP pregunta específicamente sobre "por ejemplo, usar infinito negativo", y de -infhecho es la única respuesta correcta a esto. Ha votado en contra de una respuesta correcta y útil.
cmaster - reinstalar a monica el
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.