¿Cómo inicializo un flotador a su valor máximo / mínimo?

100

¿Cómo codifico un valor máximo o mínimo absoluto para un flotante o doble? Quiero buscar el máximo / mínimo de una matriz simplemente iterando y capturando el más grande.

También hay infinitos positivos y negativos para los flotadores, ¿debería usarlos en su lugar? Si es así, ¿cómo lo denoto en mi código?

Faken
fuente

Respuestas:

151

Puede usar lo std::numeric_limitsque está definido en <limits>para encontrar el valor mínimo o máximo de tipos (siempre que exista una especialización para el tipo). También puede usarlo para recuperar el infinito (y poner un -delante para el infinito negativo).

#include <limits>

//...

std::numeric_limits<float>::max();
std::numeric_limits<float>::min();
std::numeric_limits<float>::infinity();

Como se señaló en los comentarios, min()devuelve el valor positivo más bajo posible. En otras palabras, el valor positivo más cercano a 0 que se puede representar. El valor más bajo posible es el negativo del valor máximo posible.

Por supuesto, std::max_elementexisten las funciones y min_element (definidas en <algorithm>) que pueden ser una mejor opción para encontrar el valor más grande o más pequeño en una matriz.

Yacoby
fuente
¿Cómo uso esto exactamente? ¿Qué necesito incluir? No creo que haya usado algo como esto antes.
Faken
Hmm ... esa función de elemento máximo hubiera sido muy útil ... esto es lo que sucede cuando aprendes a codificar por tu cuenta y no formalmente. Terminas reinventando la rueda 50 veces. Esta es la última vez que aprendí sobre ceil (). Gracias.
Faken
18
@Yacoby, es posible que desee aclarar que numeric_limits <float> :: min () no significa el valor más negativo, significa el positivo más pequeño.
MSN
13
@killogre: C ++ 11 agregado numeric_limits<T>::lowest(), que devuelve el valor más bajo (negativo) posible para que el tipo resuelva este problema.
Cornstalks
3
std::numeric_limits<float>::min()no no dar el valor positivo más pequeño que puede ser representado; da el número de coma flotante de precisión simple normal más pequeño . También hay números subnormales entre cero y este número. En particular, std::numeric_limits<float>::min()da 1.17549e-38pero el flotador subnormal representable más pequeño es nextafterf(0.0f, 1.0f) == 1.4013e-45f.
nibot
45

Puede usar -FLT_MAX(o -DBL_MAX) para el número negativo de magnitud máxima y FLT_MAX(o DBL_MAX) para positivo. Esto le da el rango de posibles valores flotantes (o dobles).

Probablemente no quieras usar FLT_MIN; corresponde al número positivo de menor magnitud que se puede representar con un flotante, no al valor más negativo representable con un flotante.

FLT_MINy FLT_MAXcorresponden a std::numeric_limits<float>::min()y std::numeric_limits<float>::max().

MSN
fuente
Creo que usaré esta versión en realidad, es más fácil de recordar y me crea más escenas. Enteros que puedo inicializar usando hexadecimal. Sin embargo, la mejor respuesta sigue siendo porque la respuesta también me presentó algunas funciones nuevas extremadamente útiles.
Faken
2
"[ FLT_MIN] corresponde al número positivo de menor magnitud que se puede representar con un flotante" - Esto no es cierto . Es el número normal más pequeño . También hay números subnormales.
nibot
Desea FLT_TRUE_MINel flotador más pequeño posible, que corresponde astd::numeric_limits<float>::denorm_min()
Chris Dodd
17

No hay una necesidad real de inicializar al menor / mayor posible para encontrar el menor / mayor en la matriz:

double largest = smallest = array[0];
for (int i=1; i<array_size; i++) {
    if (array[i] < smallest)
        smallest = array[i];
    if (array[i] > largest0
        largest= array[i];
}

O, si lo está haciendo más de una vez:

#include <utility>

template <class iter>
std::pair<typename iter::value_type, typename iter::value_type> find_extrema(iter begin, iter end) {
    std::pair<typename iter::value_type, typename iter::value_type> ret;
    ret.first = ret.second = *begin;
    while (++begin != end) {
        if (*begin < ret.first)
           ret.first = *begin;
        if (*begin > ret.second)
           ret.second = *begin;
   }
   return ret;
}

La desventaja de proporcionar un código de muestra: veo que otros ya han sugerido la misma idea.

Tenga en cuenta que si bien el estándar tiene un elemento_mínimo y un elemento_máximo, usarlos requeriría escanear los datos dos veces, lo que podría ser un problema si la matriz es grande. Los estándares recientes han abordado esto agregando a std::minmax_element, que hace lo mismo que el find_extremaanterior (encuentre los elementos mínimo y máximo en una colección en una sola pasada).

Editar: Abordar el problema de encontrar el valor más pequeño distinto de cero en una matriz de unsigned: observe que los valores sin signo se "envuelven" cuando llegan a un extremo. Para encontrar el valor más pequeño distinto de cero, podemos restar uno de cada uno para la comparación. Cualquier valor cero "se ajustará" al valor más grande posible para el tipo, pero se mantendrá la relación entre otros valores. Una vez que terminamos, obviamente agregamos uno al valor que encontramos.

unsigned int min_nonzero(std::vector<unsigned int> const &values) { 
    if (vector.size() == 0)
        return 0;
    unsigned int temp = values[0]-1;
    for (int i=1; i<values.size(); i++)
        if (values[i]-1 < temp)
            temp = values[i]-1;
    return temp+1;
}

Tenga en cuenta que esto todavía usa el primer elemento para el valor inicial, pero aún no necesitamos ningún código de "caso especial", ya que se ajustará al valor más grande posible, cualquier valor distinto de cero se comparará como más pequeño. El resultado será el valor más pequeño distinto de cero, o 0 si y solo si el vector no contiene valores distintos de cero.

Jerry Coffin
fuente
¡Pero obtienes un +1 de mi parte!
Dan Diplo
1
Me inicializo al máximo de minutos porque a veces quiero el valor más pequeño que no sea cero (en un caso entero sin signo, por ejemplo, mis datos tienden a tener muchos ceros poco interesantes). Me parece que tiene sentido inicializarlo en lugar de realizar comprobaciones adicionales para garantizar que el primer elemento no sea cero.
Faken
@Faken: incluso entonces puede definir una función de comparación que trate cero como el valor más grande posible, por lo que aún puede usar std::min_element:bool less_ignoring_zero(unsigned a, unsigned b) { if (a == 0) return false; if (b == 0) return true; return a < b; }
UncleBens
2
@Jerry: C ++ 0x agregará minmax_element para abordar el problema que menciona. (Pero entonces no será posible ignorar los ceros ...)
UncleBens
1
¿Qué pasa si el primer elemento no está disponible en el momento de la inicialización? Esto sucede mucho en el procesamiento en línea (como en boost :: acumuladores)
killogre
5

Para encontrar manualmente el mínimo de una matriz, no necesita saber el valor mínimo de float:

float myFloats[];
...
float minimum = myFloats[0];
for (int i = 0; i < myFloatsSize; ++i)
{
  if (myFloats[i] < minimum)
  {
    minimum = myFloats[i];
  }
}

Y código similar para el valor máximo.

Cuenta
fuente
4

¿Puedo sugerirle que inicialice sus variables de "máximo y mínimo hasta ahora" no al infinito, sino al primer número de la matriz?

Thomas Padron-McCarthy
fuente