Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/134.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 从双倍到大小的转换会产生错误的结果吗?_C++_Type Conversion_C++20 - Fatal编程技术网

C++ 从双倍到大小的转换会产生错误的结果吗?

C++ 从双倍到大小的转换会产生错误的结果吗?,c++,type-conversion,c++20,C++,Type Conversion,C++20,下面的代码可以工作。 我的问题是,2)是否应该导致非常接近1)的结果? 为什么铸造量如此之小? 其中,值得注意的是2)正好是1)的一半: std::cout这是由于规范的这一部分: 7.3.10浮点积分转换[conv.fpint] 浮点类型的prvalue可以转换为整数类型的prvalue。转换截断;也就是说,小数部分被丢弃如果目标类型中无法表示截断的值,则行为未定义。 值18446744073709551616(即截断部分)大于系统上的std::numberic_limit::max(),因此

下面的代码可以工作。 我的问题是,2)是否应该导致非常接近1)的结果? 为什么铸造量如此之小? 其中,值得注意的是2)正好是1)的一半:


std::cout这是由于规范的这一部分:

7.3.10浮点积分转换[conv.fpint]

浮点类型的prvalue可以转换为整数类型的prvalue。转换截断;也就是说,小数部分被丢弃如果目标类型中无法表示截断的值,则行为未定义。


18446744073709551616
(即截断部分)大于系统上的
std::numberic_limit::max()
,因此,该转换的行为未定义。

如果我们要计算某个无符号整数数据类型的不同值的数量 可以代表我们可以计算

 std::cout << "1)  " << std::pow(2, 8 * sizeof(size_t)) << std::endl; // yields 18446744073709551616
任何高于您希望表示的最高可能值的金额 将归结为以最大可能值+1为模的金额。(金额%(最大+1)) 正如我们在上面的例子中看到的那样,这导致了零

由于这是如此自然,标准定义了如果你转换任何 整数数据类型已签名或未签名为要转换的另一个无符号整数数据类型 以最大可能值+1为模的金额。漂亮

但是,当我们想把一个负积分转换成一个负积分时,这个简单的规则有点让我们吃惊 对于eaxample,无符号整数如-1到无符号long long。首先是0值,然后是 你扣1分。发生的是上述样本的oposite序列。看看:

  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 is 0 and now do -1
  11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 is 18446744073709551615
所以是的,将-1转换为size\u t将导致std::numeric\u limits::max()。真是难以置信 一开始,但经过一些思考和玩弄,这是可以理解的

现在是第二行代码

 std::cout << "2)  " << static_cast<size_t>(std::pow(2, 8 * sizeof(size_t))) << std::endl;
只有这11个X位表示2^n形式的指数。这意味着只有这11位必须显示64位 双精度表示2^64*1。因此,我们的大数字的表示更加紧凑 比尺寸大一倍。有人想做模最大加1的转换吗 将2^64的表示形式更改为64位行之前需要

有关浮点表示法的进一步阅读,请访问 比如说

标准上说如果你转换一个浮点值 对于无法由目标整数数据类型表示的整数,结果为UB,未定义行为

参见C++17标准ISO/IEC14882: 7.10浮点积分转换[conv.fpint]

  • 浮点类型的prvalue可以转换为整数类型的prvalue。转换截断; 也就是说,小数部分被丢弃。如果无法表示截断的值,则行为未定义 在目标类型中 所以double可以很容易地容纳2^64,这就是为什么第1行可以很容易地打印出来的原因。但它是1 太多,无法用大小表示,因此结果为UB。 因此,无论我们第二行的结果是什么,都是无关紧要的,因为它是UB

    好的,但是如果任何随机结果都可以,为什么UB结果正好是一半呢? 首先,结果来自MSVC。Clang或其他编译器可能会提供任何其他UB结果

    但让我们看看“一半”的结果,因为这很容易

       Trying to add 1 to the largest  
       11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 is 18446744073709551615
       would if only integrals would be involved lead to, 
     1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
       but thats not possible since the bit does not exist and it is not integral but double datatype and 
       hence UB, so accidentially the result is
       10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 which is 9223372036854775808
       so exactly half of the naively expected or 2^63.
    

    无关:不要为此使用
    pow
    。使用位移位:
    1您使用哪种编译器和版本?@t.niese Visual Studio 2019(v142),/std:c++latestIt并不奇怪-它是偶数
    std::pow()
    将返回一个可以正确保存值的双精度。但该值太大,无法保存在
    大小中(您将1位移到了远处),因此结果未定义,当您将其打印出来时,会得到一些随机值。在这种情况下,截断并不重要。无论是否删除了小数部分,数字都太大。@ByronB大小测试在模之前。2到64对于
    size\t
    来说太大了,在那之后所有的赌注都被取消了,但是我希望UB做模运算,因为它很简单,并且给了你0。很明显,这不是你得到的结果。
    std::pow(2,8*sizeof(size_t))
    太大了,很可能一个
    double
    无法解析-1。@ByronB
    std::pow(2,8*sizeof(size_t))-1.0也会导致
    18446744073709551616
    ,所以问题是一样的。如果我没记错编码,在你看到它之前,你必须减去1025,然后它会显著地跳跃,我想是2K。请注意,编码可能会有所不同,因此我可能在很多平台上都大错特错。
      00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 is 0 and now do -1
      11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 is 18446744073709551615
    
     std::cout << "2)  " << static_cast<size_t>(std::pow(2, 8 * sizeof(size_t))) << std::endl;
    
     0XXXXXXX XXXX0000 00000000 00000000 00000000 00000000 00000000 00000000
    
       Trying to add 1 to the largest  
       11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 is 18446744073709551615
       would if only integrals would be involved lead to, 
     1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
       but thats not possible since the bit does not exist and it is not integral but double datatype and 
       hence UB, so accidentially the result is
       10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 which is 9223372036854775808
       so exactly half of the naively expected or 2^63.