【问题标题】:Converting strings to integers the right way以正确的方式将字符串转换为整数
【发布时间】:2016-07-20 18:15:17
【问题描述】:

我想验证字符串是否为有效整数。我可以只使用 64 位整数和函数,如 std::stoullstd::stoll,但我无法验证该值是否在给定范围内。

例如,我想要一个介于 0 和 UINT64_MAX 之间的整数。如果字符串是"-1",我可以将其转换为long long,我会知道它是否定的。但是,如果字符串大于 signed long long 的最大值(通常为INT64_MAX),则溢出使其再次为负,而字符串为正整数。

一位朋友首先建议我检查减号,但我不喜欢这个解决方案,然后我考虑使用双精度,但是我知道使用双精度进行比较可能会很棘手,所以这就是我不确定的原因解决方案。

template <typename T>
inline bool is_between(const string &str,
                       T min = numeric_limits<T>::min(),
                       T max = numeric_limits<T>::max()) noexcept
{
    try {
        double value = stod(str);

        if (value < min || value > max)
            return false;
    } catch (...) {
        return false;
    }

    return true;
}

这个功能安全吗?因为我怕一串“1”会返回一个double值“0.9999999999”,那么它就不适合1到100之间的区间了。

那么我们可以这样使用函数:

cout << is_between<uint16_t>("0") << endl;
cout << is_between<uint16_t>("65535") << endl;
cout << is_between<uint16_t>("65535", 0, 2000) << endl;
cout << is_between<uint16_t>("-1") << endl;
cout << is_between<uint16_t>("800000") << endl;

【问题讨论】:

  • 为什么不把minmax转成字符串做字符串比较呢?
  • std::stoull 不会抛出异常吗?
  • @IInspectable 如果我没记错的话std::stoull 不会在输入为负数时抛出。
  • 不,std::stoull 在使用“-1”调用时不会引发异常。
  • @NathanOliver:文档似乎同意你的看法。谈论一个完全避免采取最不意外的规范的规范......

标签: c++


【解决方案1】:

您的函数不会出现您描述的错误,因为足够小的整数可以用浮点数精确表示。因此,1 的转换不能是 0.99999,因为如果 0.99999 可以用双精度表示,它们是不同的数字。可以将0.99999 转换为1

但是,如果您有足够大的数字,则限制检查不起作用,因为 64 位双精度对于小数部分的位数(通常为 54,但标准中未定义)比 64 位整数少。例如,以下程序的输出是 1 而不是 0,好像它会具有更高的精度数字。

#include <iostream>
#include <string>

int main(){
  long long v=(1l << 54) +1;
  std::cout << v-static_cast<long long>(std::stod(std::to_string(v))) << std::endl;
}

如果你真的需要接近UINT64_MAX 的数字,最好使用像Boost multiprecision 这样的库。它有一个任意精度整数cpp_int,可以从std::string 构造。

【讨论】:

  • 这怎么可能?最大双精度数远高于 64 位无符号数的最大值。您的程序还在ideone 上输出 0
  • 使用long doublestold 是有效的解决方案吗?它似乎适用于这个code
  • @mark double 的最大值更大,但由于某些位用于表示指数,它不能代表 64 位整数可以的所有数字。换句话说,对于足够大的双精度数,两个连续数字之间的差异大于一。 ideone有些奇怪。 long long v=(1l &lt;&lt; 54) +1; 的结果是 1。如果您只是将该计算的结果替换为它,它似乎给出了我的期望。见ideone。如果long double 是 128 位并且尾数在您的系统中超过 64 位,它将起作用。
猜你喜欢
  • 2020-06-03
  • 2013-05-30
  • 2012-12-21
  • 1970-01-01
  • 1970-01-01
  • 2012-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多