使用 switch 语句进行范围检查

Range checks using a switch statement

我的老师分配了一个程序来使用 if-else 语句和 switch 语句,所以我们了解如何实现这两者。该程序要求我们提示用户分别以磅和米为单位输入他们的体重和身高。这是我的尝试:

没有开关

#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;
    }
}

随开关

#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;
    }
}

这就是我想到的方式,包括一个 switch 语句。有什么方法可以将第一个代码块实现为 switch 语句吗?

我几乎可以肯定既不能使用范围也不能使用双精度 (18.5)。我给我的老师发了邮件,他们给了我一个类似

的答案

It may not make sense to you, but sometimes you are going to have to write a program that does not make sense. I am not saying that you don't have legitimate questions, but if anyone can figure it out you can. But then, maybe it can't be figured out. That's the challenge".

所以,我想问:是否有一些方法可以只对第一个代码块使用 switch 语句,或者我在代码中使用 switch 语句的最佳方法是什么,即使它在没必要?

C++ 中的开关仅允许您检查整数和字符的值。

BMI 是双精度类型,因此无法在开关中检查其值。

在带有开关的解决方案中,您还应该将变量 BMI 声明为双精度。如果将其声明为整数,则所有小数结果都将转换为整数,并且您将丢失小数位。

除非你有一个绝对可怕的编译器扩展,否则你不能 switch 在 C++ 中的范围上。

但如果您创建 std::vector BMI 范围,则可以优雅地使用开关:

std::vector<double> v = {18.5, 25.0 /*etc*/}

然后使用 std::lower_boundstd::distance 来获得给定 BMI 在上述范围内的位置。 这个是你switch的数量。

然后您可以更进一步并定义 std::vector<std::string> 输出消息。那么你既不需要 switch 也不需要 if 块!所有的选择逻辑都委托给了std::lower_bound.

我故意没有给你完整的代码:我相信这些提示已经足够了。

你不能在 switch 中使用 double。文档说:

switch ( expression )
   case constant-expression : statement
   [default   : statement]

The expression must be of an integral type or of a class type for which there is an unambiguous conversion to integral type. Integral promotion is performed as described in Integral Promotions.

旁注:

有些编译器(如 Clang 3.5.1)允许 case x ... y 作为 C++ 语言的扩展。但这也适用于整数数据类型。像

switch(x){
       case 0:
            cout << "Test1";
            break;
       case 0 ... 9:
            cout << "Test2";
            break;

您可以这样做:

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;
}

我也忍不住注意到这一点,因为您使用的是 if-else,所以您可以避免 else-if 语句中的第一个条件,例如:

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;
}

除此之外,您的两个实现看起来都不错。

一如既往地在 C++ 中,支持标准库算法。在这种情况下,您想进行范围查找。使用有序的边界序列很容易:

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;
};

其实我建议你

  • 考虑不使用 switch(请参阅下面的 奖励 部分)
  • 让它成为一个函数而不是直接打印
  • 下降 using namespace std(参见 Why is "using namespace std" considered bad practice?

观看现场演示 on 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";
    }
}

版画

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

奖金

不需要使用switch:

可以更优雅

Live On Coliru

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));
}

您可以从 array/vector 动态计算案例标签,而不是硬编码 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;
  }

}

(如果您真的愿意,您甚至可以制作 seg 函数 constexpr)。

我们需要适应输入,所以,而不是这个代码:

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;

    }

你需要这样的东西

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;
}

逻辑是将if-elses转换成数学公式,返回一个int。