c++ - son - objetivo de la declaracion de cambio
Verificaciones de rango usando una declaración de cambio (7)
A menos que tenga una extensión de compilador absolutamente espantosa, no puede switch
un rango en C ++.
Pero podría usar un interruptor elegantemente si crea un std::vector
de los rangos BMI:
std::vector<double> v = {18.5, 25.0 /*etc*/}
Luego use std::lower_bound
junto con std::distance
para obtener la posición de un BMI dado en los rangos anteriores. Esta es la cantidad que switch
.
Luego, puede ir una etapa más allá y definir un std::vector<std::string>
de los mensajes de salida. ¡Entonces no necesitas ni un switch
ni un bloque if
! Toda la lógica de selección se delega a std::lower_bound
.
Deliberadamente no te he dado el código completo: confío en que estos consejos sean suficientes.
Mi maestra ha asignado un programa para usar las declaraciones if-else
y las declaraciones switch
, así que entendemos cómo implementar ambas. El programa nos pidió que solicitemos al usuario que ingrese su peso y altura en libras y metros respectivamente. Este es mi intento:
Sin el interruptor
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
double height, weight, BMI, heightMeters, weightKilo;
const double KILOGRAMS_PER_POUND = 0.45359237;
const double METERS_PER_INCH = 0.0245;
cout << "Please enter your height (inches) and weight (pounds)" << endl;
cin >> height >> weight;
weightKilo = weight*KILOGRAMS_PER_POUND;
heightMeters = height*METERS_PER_INCH;
BMI = weightKilo / (heightMeters*heightMeters);
if (BMI < 18.5) {
cout << "You are underweight " << endl;
}
else if (BMI >= 18.5 && BMI < 25.0) {
cout << "You are normal" << endl;
}
else if (BMI >= 25.0 && BMI < 30.0) {
cout << "You are overweight" << endl;
}
else if (BMI >= 30.0 && BMI < 35) {
cout << "You are obese" << endl;
}
else {
cout << "You are gravely overweight" << endl;
}
}
Con el interruptor
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
double height, weight, heightMeters, weightKilo;
int BMI, q;
const double KILOGRAMS_PER_POUND = 0.45359237;
const double METERS_PER_INCH = 0.0245;
cout << "Please enter your height (inches) and weight (pounds)" << endl;
cin >> height >> weight;
weightKilo = weight*KILOGRAMS_PER_POUND;
heightMeters = height*METERS_PER_INCH;
BMI = weightKilo / (heightMeters*heightMeters);
if (BMI < 18.5) {
q = 1;
}
else if (BMI >= 18.5 && BMI < 25.0) {
q = 2;
}
else if (BMI >= 25.0 && BMI < 30.0) {
q = 3;
}
else if (BMI >= 30.0 && BMI < 35) {
q = 4;
}
else {
q = 5;
}
switch (q) {
case 1: cout << "You are underweight" << endl; break;
case 2: cout << "You are a normal weight " << endl; break;
case 3: cout << "You are overweight" << endl; break;
case 4: cout << "You are obese" << endl; break;
case 5: cout << "You are gravely overweight" << endl; break;
}
}
Esta fue la forma en que pensé, para incluir una declaración de cambio. ¿Hay alguna forma de implementar el primer bloque de código para simplemente una declaración de cambio?
Estaba casi seguro de que no se podía hacer para usar rangos ni para usar dobles (18.5). Le envié un correo electrónico a mi maestro y me dieron una respuesta a lo largo de las líneas de
Puede que no tenga sentido para usted, pero a veces tendrá que escribir un programa que no tiene sentido. No estoy diciendo que no tenga preguntas legítimas, pero si alguien puede resolverlo, puede hacerlo. Pero luego, tal vez no se pueda descifrar. Ese es el desafío ".
Entonces, estoy preguntando: ¿hay algún método para usar una declaración switch para el primer bloque de código, o es lo que hice de la mejor manera para usar una declaración switch en el código, incluso si no es necesario?
Como siempre en C ++, favorezca los algoritmos de la biblioteca estándar. En este caso, quiere hacer una búsqueda de rango. Esto es fácil con una secuencia ordenada de límites:
double const boundaries[] = { 18.5, 25, 30, 35 };
switch (upper_bound(begin(boundaries), end(boundaries), BMI) - boundaries) {
case 0: cout << "You are underweight " << endl; break;
case 1: cout << "You are normal" << endl; break;
case 2: cout << "You are overweight" << endl; break;
case 3: cout << "You are obese" << endl; break;
case 4: cout << "You are gravely overweight" << endl; break;
};
En realidad, te sugiero
- considere no usar un
switch
(vea la sección de BONIFICACIÓN a continuación) - hacer que una función en lugar de imprimir directamente
- drop
using namespace std
(ver ¿Por qué "usar namespace std" se considera una mala práctica? )
Vea una demostración en vivo en Coliru
#include <iostream>
#include <algorithm>
const char* bmi_classification(double bmi) {
static double const boundaries[] = { 18.5, 25, 30, 35 };
double const* lookup = std::upper_bound(std::begin(boundaries), std::end(boundaries), bmi);
switch (lookup - std::begin(boundaries)) {
case 0: return "underweight";
case 1: return "normal";
case 2: return "overweight";
case 3: return "obese";
case 4: return "gravely overweight";
}
throw std::logic_error("bmi_classification");
}
int main() {
for (double BMI : { 0.0, 18.4999, 18.5, 24.0, 25.0, 29.0, 30.0, 34.0, 35.0, 999999.0 }) {
std::cout << "BMI: " << BMI << " You are " << bmi_classification(BMI) << "/n";
}
}
Huellas dactilares
BMI: 0 You are underweight
BMI: 18.4999 You are underweight
BMI: 18.5 You are normal
BMI: 24 You are normal
BMI: 25 You are overweight
BMI: 29 You are overweight
BMI: 30 You are obese
BMI: 34 You are obese
BMI: 35 You are gravely overweight
BMI: 999999 You are gravely overweight
PRIMA
Puedes ser más elegante sin el requisito de usar el switch
:
const char* bmi_classification(double bmi) {
constexpr int N = 5;
static constexpr std::array<char const*, N> classifications {
{ "underweight", "normal", "overweight", "obese", "gravely overweight" }};
static constexpr std::array<double, N-1> ubounds {
{ 18.5, 25, 30, 35 }};
auto lookup = std::upper_bound(std::begin(ubounds), std::end(ubounds), bmi);
return classifications.at(lookup - std::begin(ubounds));
}
Necesitamos encajar en la entrada, entonces, en lugar de este código:
if (BMI < 18.5) {
q = 1;
}
else if (BMI >= 18.5 && BMI < 25.0) {
q = 2;
}
else if (BMI >= 25.0 && BMI < 30.0) {
q = 3;
}
else if (BMI >= 30.0 && BMI < 35) {
q = 4;
}
else {
q = 5;
}
switch (q) {
case 1: cout << "You are underweight" << endl; break;
case 2: cout << "You are a normal weight " << endl; break;
case 3: cout << "You are overweight" << endl; break;
case 4: cout << "You are obese" << endl; break;
case 5: cout << "You are gravely overweight" << endl; break;
}
Necesitas algo como
switch (1 + (BMI >= 18.5) + (BMI >= 25) + (BMI >= 30) + (BMI >= 35)) {
case 1: cout << "You are underweight" << endl; break;
case 2: cout << "You are a normal weight " << endl; break;
case 3: cout << "You are overweight" << endl; break;
case 4: cout << "You are obese" << endl; break;
case 5: cout << "You are gravely overweight" << endl; break;
}
La lógica es convertir los if-elses en una fórmula matemática, devolviendo un int.
No puedes usar un doble dentro de un interruptor. La documentación dice:
switch ( expression )
case constant-expression : statement
[default : statement]
La expresión debe ser de un tipo integral o de un tipo de clase para el que exista una conversión no ambigua al tipo integral. La promoción integral se realiza como se describe en Promociones integrales.
En otros comentarios:
Hay algunos compiladores (como Clang 3.5.1) que permiten el case x ... y
como una extensión del lenguaje C ++. Pero eso también es para un tipo de datos integral. Algo como
switch(x){
case 0:
cout << "Test1";
break;
case 0 ... 9:
cout << "Test2";
break;
Puede calcular las etiquetas de sus cajas dinámicamente desde una matriz / vector en lugar de codificar una expresión if / else:
//#include "stdafx.h"
#include <iostream>
using namespace std;
inline int seg(double d){ //calculate segment for a BMI of d
constexpr double segs[] = { 18.5, 25, 30, 35 };
constexpr int n = sizeof(segs)/sizeof(double);
int r; for(r=0; r<n; r++)
if(d<segs[r]) return r;
return r;
}
int main()
{
double height, weight, heightMeters, weightKilo;
int BMI, q;
const double KILOGRAMS_PER_POUND = 0.45359237;
const double METERS_PER_INCH = 0.0245;
cout << "Please enter your height (inches) and weight (pounds)" << endl;
cin >> height >> weight;
weightKilo = weight*KILOGRAMS_PER_POUND;
heightMeters = height*METERS_PER_INCH;
BMI = weightKilo / (heightMeters*heightMeters);
switch (seg(BMI)) {
case 0: cout << "You are underweight" << endl; break;
case 1: cout << "You are a normal weight " << endl; break;
case 2: cout << "You are overweight" << endl; break;
case 3: cout << "You are obese" << endl; break;
case 4: cout << "You are gravely overweight" << endl; break;
}
}
(Incluso podría hacer que las funciones seg constexpr
si realmente quisiera).
Puedes hacer algo como:
switch ((round)BMI)
{
case 1: case 2: case 3: .... case 15: case 16: case 17: cout<< "You are underweight " << endl; break;
case 18: ... case 24: cout << "You are normal" << endl; break;
case 25: ... case 29: cout << "You are overweight" << endl; break;
case 30: ... case 34: cout << "You are obese" << endl; break;
default: cout << "You are gravely overweight" << endl;
}
Además, no pude evitar darme cuenta de que, dado que está utilizando if-else
, puede evitar la primera condición en else-if
sentencias else-if
como:
if (BMI < 18.5)
{
cout << "You are underweight " << endl;
}
else if (BMI < 25.0)
{
cout << "You are normal" << endl;
}
else if (BMI < 30.0)
{
cout << "You are overweight" << endl;
}
else if(BMI < 35)
{
cout << "You are obese" << endl;
}
else
{
cout << "You are gravely overweight" << endl;
}
Aparte de esto, ambas implementaciones se ven bien.
Un interruptor en C ++ solo le permite verificar los valores de enteros y caracteres.
El BMI es un tipo doble, por lo que no es posible verificar su valor en un interruptor.
En su solución con el interruptor también debe declarar el IMC variable como el doble. Si lo declaras como entero, todos los resultados decimales se convertirán en un entero, y perderás los decimales.