La respuesta de SourceCode es muy buena, pero querría añadir detalles que no ha comentado.
Para empezar, quiero señalar un problema semántico: estás comparando TRES números pero tu mensaje de error se refiere a DOS:
cout<<"Ambos numeros son iguales";
El mensaje no debería mencionar Ambos
, es muy confuso (y una fuente de errores comunes) que el código diga una cosa y la información que aparece por pantalla diga otra.
Comparaciones.
Seguidamente, como te han señalado, la instrucción (n1=n2=n3)
no compara los tres números, esa instrucción se desglosa de derecha a izquierda así:
- Asigna a
n2
el valor de n3
.
- Devuelve
n2
.
- Asigna a
n1
el valor de n2
.
- Devuelve
n1
.
Así que al final de la instrucción los tres números tendrán el valor de n3
pero eso no es lo que hace que se cumpla la condición if ((n1=n2=n3))
si no el hecho de que n1
no es 0
.
Al final de la instrucción de doble asignación se devuelve n1
(que ha recibido el valor de n2
que ha recibido el valor de n3
) en C++ cualquier expresión numérica puede ser convertida implícitamente a una expresión booleana siguiendo las siguientes normas:
- Si el valor de la expresión numérica es
0
se considera que su valor booleano es false
.
- Si el valor de la expresión no es
0
se considera que su valor booleano es true
.
Por lo tanto, si en tu código hubieses dado valor 0
a n3
no se habría cumplido la condición if ((n1=n2=n3))
ya que n1
(que recibió el valor de n2
que recibió el valor de n3
) sería 0
y se consideraría false
.
Si quieres comprobar si los tres valores son iguales, basta con comparar el primero con el segundo y el segundo con el tercero usando el operador de comparación (==
) (no el de asignación (=
)) y enlazando la comparación con un Y lógico (&&
):
if (n1 == n2 && n2 == n3)
cout << "Los números son iguales\n";
Nunca podrás comprobar si los tres valores son iguales encadenando tres operadores de comparación (==
):
if (n1 == n2 == n3) // Esto no funciona!
Ya que la instrucción anterior se desglosa de derecha a izquierda así:
- Compara
n2
(de tipo float
) con n3
(de tipo float
).
- Devuelve un valor booleano.
- Compara
n1
(de tipo float
) con un valor booleano (de tipo bool
).
- Convierte
n1
a bool
siguiendo las normas mencionadas antes.
- Compara
n1
convertido a bool
con el booleano de la primera comparación.
De esta manera, si n2
y n3
son iguales y n1
no es 0
se cumplirá la condición aunque n1
sea diferente a n2
y n3
.
El máximo.
Es tremendamente confuso encadenar comparaciones para determinar cuál es el mayor de una serie de números, yo aconsejo usar la función std::max
, tu código podría quedar así:
#include <iostream>
#include <algorithm>
int main() {
using namespace std;
float n1, n2, n3;
cout << "Escriba tres numeros: \n";
cin >> n1 >> n2 >> n3;
if (n1 == n2 && n2 == n3) {
cout << "Los numeros son iguales\n";
}
else {
cout << "El mayor es: " << max(n1, max(n2, n3)) << '\n';
}
return 0;
}
Avanzado.
Si quieres generalizar la comprobación de valores y la búsqueda del máximo para que reciban una cantidad arbitraria de parámetros, podrías usar plantillas variádicas:
template <typename T, typename ... VALORES>
T multi_max(const T &valor, const VALORES & ... valores)
{
if constexpr (sizeof...(VALORES) == 0)
return valor;
else
return std::max(valor, multi_max(valores ...));
}
template <typename T, typename ... VALORES>
bool todos_iguales(const T &a, const T &b, const VALORES & ... valores)
{
if constexpr (sizeof...(VALORES) == 0)
return a == b;
else if constexpr (sizeof...(VALORES) == 1)
return a == b && todos_iguales(b, valores ...);
else
return a == b && todos_iguales(valores ...);
}
Así:
if (todos_iguales(n1, n2, n3) {
cout << "Los numeros son iguales\n";
}
else {
cout << "El mayor es: " << multi_max(n1, n2, n3) << '\n';
}
Otras cosas a tener en cuenta.
A parte de corregir la primera comparación y usar max
para buscar el máximo he hecho los siguientes cambios:
- He movido la cláusula
using namespace std;
a main
. Es una buena práctica evitar usar esa cláusula en el ámbito global, úsala en el ámbito más pequeño posible. Lee este hilo para saber por qué.
- He substituido
std::endl
por \n
ya que puede causar problemas de rendimiento. Lee este hilo para saber por qué.
- He añadido mayor separación en los símbolos para dejar al código respirar. En los 90 teníamos pantallas de 80 caracteres de ancho y 25 líneas de alto, por entonces tenía sentido apretujar el código para que cupiera en la pantalla. Hoy día tenemos pantallas enormes y separar las cosas hace que el código sea más legible.