atoi()用于int128_t类型

Abh*_*yal 15 c c++ int

如何argvint128_t支持下使用值?我知道atoi()暴露的函数和函数系列,<cstdlib>但不知怎的,我找不到一个int128_t固定宽度整数.这可能是因为这type不受c或c ++标准的支持,但是我有什么方法可以让这段代码工作吗?

#include <iostream>

int main(int argc, char **argv) {
    __int128_t value = atoint128_t(argv[1]);
}
Run Code Online (Sandbox Code Playgroud)

几乎所有发布的答案对我来说都足够好了,但我选择的是当前代码的解决方案,所以也要查看其他答案.

dbu*_*ush 5

这是实现此目的的简单方法:

__int128_t atoint128_t(const char *s)
{
    const char *p = s;
    __int128_t val = 0;

    if (*p == '-' || *p == '+') {
        p++;
    }
    while (*p >= '0' && *p <= '9') {
        val = (10 * val) + (*p - '0');
        p++;
    }
    if (*s == '-') val = val * -1;
    return val;
}
Run Code Online (Sandbox Code Playgroud)

此代码检查每个字符以查看它是否是数字(带有可选的前导 + 或 -),如果是,则将当前结果乘以 10 并添加与该数字关联的值。如果需要的话,它会反转符号。

请注意,此实现不检查溢出,这与 的行为一致atoi

编辑:

修改后的实现,int128_MIN通过根据符号添加或减去每个数字的值并跳过前导空格来覆盖大小写。

int myatoi(const char *s)
{
    const char *p = s;
    int neg = 0, val = 0;

    while ((*p == '\n') || (*p == '\t') || (*p == ' ') ||
           (*p == '\f') || (*p == '\r') || (*p == '\v')) {
        p++;
    }
    if ((*p == '-') || (*p == '+')) {
        if (*p == '-') {
            neg = 1;
        }
        p++;
    }
    while (*p >= '0' && *p <= '9') {
        if (neg) {
            val = (10 * val) - (*p - '0');
        } else {
            val = (10 * val) + (*p - '0');
        }
        p++;
    }
    return val;
}
Run Code Online (Sandbox Code Playgroud)


Jon*_*nas 4

这是一个 C++ 实现:

#include <string>
#include <stdexcept>

__int128_t atoint128_t(std::string const & in)
{
    __int128_t res = 0;
    size_t i = 0;
    bool sign = false;

    if (in[i] == '-')
    {
        ++i;
        sign = true;
    }

    if (in[i] == '+')
    {
        ++i;
    }

    for (; i < in.size(); ++i)
    {
        const char c = in[i];
        if (not std::isdigit(c)) 
            throw std::runtime_error(std::string("Non-numeric character: ") + c)
        res *= 10;
        res += c - '0';
    }

    if (sign)
    {
        res *= -1;
    }

    return res;
}

int main()
{
  __int128_t a = atoint128_t("170141183460469231731687303715884105727");
}
Run Code Online (Sandbox Code Playgroud)

如果你想测试它,那么这里有一个流运算符。

表现

我进行了一些性能测试。我生成了 100,000 个均匀分布在__int128_t. 然后我每个都转换了2000次。所有这些(200,000,000)次转换都在大约 12 秒内完成。使用此代码:

#include <iostream>
#include <string>
#include <random>
#include <vector>
#include <chrono>

int main()
{
    std::mt19937 gen(0);
    std::uniform_int_distribution<> num(0, 9);
    std::uniform_int_distribution<> len(1, 38);
    std::uniform_int_distribution<> sign(0, 1);

    std::vector<std::string> str;

    for (int i = 0; i < 100000; ++i)
    {
        std::string s;
        int l = len(gen);
        if (sign(gen))
            s += '-';
        for (int u = 0; u < l; ++u)
            s += std::to_string(num(gen));
        str.emplace_back(s);
    }

    namespace sc = std::chrono;
    auto start =  sc::duration_cast<sc::microseconds>(sc::high_resolution_clock::now().time_since_epoch()).count();
    __int128_t b = 0;
    for (int u = 0; u < 200; ++u)
    {
        for (int i = 0; i < str.size(); ++i)
        {
            __int128_t a = atoint128_t(str[i]);
            b += a;
        }
    }
    auto time =  sc::duration_cast<sc::microseconds>(sc::high_resolution_clock::now().time_since_epoch()).count() - start;
    std::cout << time / 1000000. << 's' << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

  • @Jonas,如果您创建一个包含 C 字符串的*第二个*向量,那么很容易计算出来。也就是说,如果目标 CPU 支持至少 64 位数字相乘,实际性能可能会相当好,而我的方法则受到以下事实的影响:我无法在 C 中使用“硬件进位”,因此会浪费时间检查单个位。因此,对于“仅”128 位,您的“天真的”方法很可能更快。不过,数字越大——你知道;) (3认同)
  • @Jonas我会将其添加到我的答案中,因此它看起来不像是试图“抹黑”这种天真的方法。 (2认同)
  • 我很遗憾地看到这段代码比精心打磨的 C 版本获得了更多的票数。我想 java 或 javascript 版本会更有价值。 (2认同)