如何在 C++ 中编写八进制浮点文字?

How to write an octal floating point literal in C++?

不知何故,我一直认为浮点值和整数值的处理方式相同,只是其中一个会带有“.”。字符.

所以对于这样的代码:

auto i = 0100;
std::cout << i;

我得到了预期的输出 64;

但是,当我尝试以下代码时:

auto d = 0100.0;
std::cout << d;

我得到输出 100,这不是预期的结果。现在浮点部分可能不处理前导 0。所以我尝试了一些确实应该有效的方法:

auto d = 1.0e-010;
std::cout << d;

因为指数本身实际上是一个整数值,所以理解八进制值是有道理的,但输出是 1e-10.

这是标准问题还是 g++(我的编译器)问题?我将如何写一个八进制浮点数?

十六进制似乎表现不同:

auto d = 0x100.0;

给予error: hexadecimal floating constants require an exponent

但是:

auto d = 0x1e3;
std::cout << d;

产生 483。而

auto d = 0x1e0x3;

给予error: unable to find numeric literal operator ‘operator"" x3’

在 C++ 中不能用八进制写浮点文字。您将不得不接受小数。

标准 C++ 也不允许十六进制浮点文字。但是,C 支持(自 C99 起)并且支持它的编译器也可能允许 C++ 中的十六进制作为语言的扩展。

Hexadecimal seem to behave differently

是的。有关如何编写十六进制浮点文字的详细信息,请参阅this answer

您可以使用 C++11 的用户定义字面值自己制作一个。

#include <iostream>
#include <cmath>
using namespace std;

long double operator"" _oct (long double oct)
{
    int i = 0;
    long double rem, fract, decimal = 0.0;
    long whole = (long)oct;
    fract = oct - whole;

    // whole part
    while (whole != 0)
    {
        rem = fmod(whole,10);
        whole/=10;
        decimal += rem*pow(8,i++);
    }
    i = 1; 
    // fractional part
    while(fract != 0){
        fract *= 10;
        rem = round(fract);
        decimal += rem*pow(8,-i++);
        fract -= rem;
    }
    return decimal;
}

int main() {
    cout << 10.1_oct; //8.125
    return 0;
}

user2079303 and blojayble 都给出了很好的答案,但是,都有点不完整。因此,这里是对它们的扩展以及找到的其他信息。

C++ 中没有八进制浮点数……这是有原因的

该标准没有定义八进制浮点数,编译器严格遵守这一特定规则。前导 0 被读取为整个部分或指数中的另一个十进制数字。

可能的原因是像 0.2 这样的数字含糊不清。大多数人的意思是这个⅕;而如果八进制浮点数是真实的,那将是 ¼,原因与 0 是八进制文字 (see here).

的原因相同。

C++中没有十六进制浮点数,但是...

...,但是C里面有,那么多编译器都允许用,就是有点奇怪。

首先,没有指数部分它们就无法工作。所以写入 0x12a.b3 可能不起作用。

其次,在十六进制表示法中,e 不是指数,因为它是数字 14。因此,使用 p(可能表示类似 "power" 的意思)。

第三,十六进制的指数不是10(当然),但也不是16(出于某种原因)。相反,它是 2。所以 0x12.4p3 变成 ( 1×16¹ + 2×16⁰ + 4×16⁻¹ ) × 2³ = ( 16 + 2 + ¼ ) × 8 = 146.

在C++11中定义自己的字面值相对简单

blojayble 提供了自己的实现,但我认为最好将其重做成constexpr。最终结果是下面的代码:

constexpr unsigned long long operator"" _oct(unsigned long long l)
{
    return
        (l < 9) ? l :
        operator"" _oct(l/10)*8 + l%10;
}
constexpr long double operator"" _oct(long double d)
{
    return
        (d == 0) ? 0.0 :
        (d < 1) ? 0.125*(((int)(d*10)) + operator"" _oct(d*10-((int)(d*10)))) :
        operator"" _oct((unsigned long long)d) + operator"" _oct(d-(unsigned long long)d);
}