为什么long long n = 2000*2000*2000*2000;溢出?

如何解决为什么long long n = 2000*2000*2000*2000;溢出?

long long int n = 2000*2000*2000*2000;    // overflow

long long int n = pow(2000,4);            // works
long long int n = 16000000000000;         // works

为什么第一个溢出(乘以整数文字常量以分配给 long long)?

它与第二个或第三个有什么不同?

解决方法

因为 2000 是一个 int,通常是 32 位。只需使用 2000LL

@AdrianMole 在评论中建议使用 LL 后缀代替 ll。请检查他的answer

默认情况下,整数文字是可以保存其值但不小于 int 的最小类型。 2000 可以很容易地存储在 int 中,因为标准保证它至少是一个有效的 16 位类型。

算术运算符总是使用存在的较大但不小于 int 的类型调用:

  • char*char 将被提升为 operator*(int,int)->int
  • char*int 调用 operator*(int,int)->int
  • long*int 调用 operator*(long,long)->long
  • int*int 仍然调用 operator*(int,int)->int

类型不依赖于结果是否可以存储在推断类型中。这正是您的情况发生的问题 - 乘法是用 int 完成的,但结果溢出,因为它仍然存储为 int

C++ 不支持像 Haskell 那样基于目的地推断类型,因此赋值无关紧要。

,

第一行代码的 RHS 上的常量(文字)是 int 值(不是 long long int)。因此,乘法是使用 int 算法执行的,这会溢出。

要解决此问题,请使用 long long 后缀使常量 LL

long long int n = 2000LL * 2000LL * 2000LL * 2000LL;

cppreference

事实上,正如 Peter Cordes 的评论中所指出的,LL 后缀实际上只是需要在第一个(最左边)或第二个常量上。这是因为,当两个不同的 ranks 类型相乘时,较低等级的操作数会提升为较高等级的类型,如下所述:Implicit type conversion rules in C++ operators。此外,由于 *(乘法)运算符具有 left-to-right associativity,第一次乘法的“提升”结果将该提升传播到第二次和第三次。

因此,以下任一行也不会溢出:

long long int n1 = 2000LL * 2000 * 2000 * 2000;
long long int n2 = 2000 * 2000LL * 2000 * 2000;

注意:尽管小写后缀(如 2000ll 中的)是有效的 C++,并且对于编译器来说完全明确,但是有一个 general consensuslonglong long 整数文字中应该避免使用小写字母 'ell',因为它很容易被人类读者误认为是数字 { {1}}。因此,您会注意到此处提供的所有答案都使用了 1(大写后缀)。

,

2000*2000*2000*2000 是 4 个 int 值的乘积,它返回一个 int 值。当您将此 int 值分配给 long long int n 时,溢出已经发生(如果 int 是 32 位,则结果值将不适合)。

你需要确保不会发生溢出,所以当你写

long long int n = static_cast<long long int>(2000)*2000*2000*2000;

你确保你正在做一个 long long int 乘法(long long int 乘以 int 返回一个 long long int,所以在你的情况下没有溢出)。

更短(更好)的方法是写 2000LL2000ll 而不是 static_cast。这为整数文字提供了正确的类型。这对于适合 int 的 2000 不需要,但对于不适合 int 的更高值则需要。

long long int n = 2000LL*2000*2000*2000;
long long int n = 2000LL*2000LL*2000LL*2000LL;
,

其他答案(截至撰写本文时)似乎不够明确,无法回答所述问题。我会努力填补这个空白。

为什么第一个溢出(乘以整数文字常量以分配给 long long)?

表达式

long long int n = 2000*2000*2000*2000;

评估如下:

long long int n = ((2000*2000)*2000)*2000;

步骤在哪里(假设 32 位 int):

  1. (2000*2000) 是两个 int 值的乘积,产生 4000000,另一个 int 值。
  2. ((2000*2000)*2000) 是上面产生的 int 值 4000000 与 int 值 2000 的乘积。如果该值可以放入 int,这将产生 8000000000。但是我们假设的 32 位 int 可以存储最大值 231-1=2147483647。所以我们在这一点上就溢出了。
  3. 如果上面没有溢出,就会发生下一次乘法。
  4. 将生成的 int 乘积赋值给 long long 变量(如果不是溢出),这将保留值。

由于我们确实有溢出,该语句具有未定义的行为,因此不能保证第 3 步和第 4 步。

它与第二个或第三个有什么不同?

  • long long int n = pow(2000,4);

pow(2000,4)20004 转换为 double(参见 some docs on pow),然后函数实现尽最大努力产生一个很好的近似值结果,作为 double。然后赋值将此 double 值转换为 long long

  • long long int n = 16000000000000;

文字 16000000000000 太大而无法放入 int,因此它的类型是下一个可以适合该值的有符号类型。它可能是 longlong long,具体取决于平台。有关详细信息,请参阅 Integer literal#The type of the literal。然后赋值将此值转换为 long long(或者只是写它,如果文字的类型已经是 long long)。

,

第一个是使用整数(通常为 32 位)的乘法。它溢出是因为这些整数不能存储 2000^4。然后将结果强制转换为 long long int

第二个调用 pow 函数,该函数将第一个参数强制转换为 double 并返回一个 double。然后将结果强制转换为 long long int。在这种情况下没有溢出,因为数学是在 double 值上完成的。

,

您可能想在 C++ 中使用以下内容来理解这一点:

#include<iostream>
#include<cxxabi.h>

using namespace std;
using namespace abi;

int main () {
    int status;
    cout << __cxa_demangle(typeid(2000*2000*2000*2000).name(),&status);
}

如您所见,类型为 int

在 C 中,您可以使用 (courtesy of):

#include <stdio.h>
#include <stddef.h>
#include <stdint.h>

#define typename(x) _Generic((x),/* Get the name of a type */             \
                                                                                  \
        _Bool: "_Bool",unsigned char: "unsigned char",\
         char: "char",signed char: "signed char",\
    short int: "short int",unsigned short int: "unsigned short int",\
          int: "int",unsigned int: "unsigned int",\
     long int: "long int",unsigned long int: "unsigned long int",\
long long int: "long long int",unsigned long long int: "unsigned long long int",\
        float: "float",double: "double",\
  long double: "long double",char *: "pointer to char",\
       void *: "pointer to void",int *: "pointer to int",\
       char(*)[]: "pointer to char array",default: "other")


unsigned int a = 3;
int main() {
    printf("%s",typename(a-10));
    return 0;
}

这里表达式的类型是unsigned int,因为类型不匹配隐式将类型升级为unsigned intint之间的最大类型,即unsigned intunsigned int 将下溢到一个大的正数,当分配给或解释为 int 时,这将是预期的负数。无论涉及的值如何,计算结果始终为 unsigned int

C

没有后缀的整数文字的最小默认类型是int,但只有当文字超过这个值时,它的类型才会变成unsigned int;如果大于它,则给定 long int 的类型,因此 2000 年都是 int。然而,在文字上执行的 表达式 的类型,使用一元或二元运算符,使用隐式类型层次结构来决定类型,而不是结果的值(与使用长度的文字本身不同)决定类型的文字)。为了解决这个问题,您必须在 2000 年代使用长后缀 ul 来明确指定文字的类型。

同样,十进制文字的默认类型是 double,但这可以通过 f 后缀更改。前缀不会改变十进制或整数文字的类型。

字符串文字的类型是char [],虽然它实际上是一个const char [],并且只是.rodata中该字符串文字实际表示中第一个字符的地址,并且可以像使用一元符号 &"string" 的任何数组一样获取地址,它与 "string" 具有相同的值(地址),只是类型不同(char (*)[7] 与 {{1 }}; char[7]"string" 不只是(在编译器级别)指向数组的指针,它数组,而一元&符号仅提取指向数组的指针大批)。 char[] 前缀将其更改为 u 数组,即 char16_tunsigned short int 前缀将其更改为 U 数组,这是一个 char32_t;并且 unsigned int 前缀将其更改为 L 数组,它是一个 wchar_tintu8 并且不带前缀的字符串使用特定于实现的编码,通常与 char 相同,即 UTF-8,ASCII 是其中的一个子集。一个 raw (R) prefix 仅适用于字符串文字(并且仅适用于 GNU C(u8 以后))可以作为前缀,即 std=gnu99uR,但这不会影响类型.

字符文字的类型是 u8R 除非以 int 为前缀(uu'a')或 unsigned short intU 为 { {1}})。 U'a'unsigned int 在用于字符文字时都是 u8。字符串或字符文字中的转义序列不会影响编码和类型,它只是将要编码的字符实际呈现给编译器的一种方式。

复数文字Lint的类型是10i+1,其中实部和虚部都可以有后缀,比如10j+1,在这个case 使虚部变长,整体类型为complex int,并升级了实部和虚部的类型,所以不管你把后缀放在哪里,也不管你把它放在哪里。不匹配将始终使用两个后缀中最大的作为整体类型。

使用显式转换而不是文字后缀总是会导致正确的行为,如果您正确使用它并且知道它截断/扩展的语义差异(符号扩展 10Li+1;零扩展 {{ 1}} – 这是基于被转换的文字或表达式的类型,而不是被转换为的类型,因此 complex long int 被符号扩展为 signed) 一个文字到一个表达式那种类型,而不是文字本身就具有那种类型。

C++

enter image description here

同样,最小默认类型是最小文字基数的 unsigned。文字基础即文字的实际值,后缀根据下表影响最终文字类型,其中在每个后缀的每个框中,最终类型的顺序根据实际的大小从最小到最大列出字面基础。对于每个后缀,文字的最终类型只能等于或大于后缀类型,并基于文字库的大小。 C 表现出相同的行为。当大于 signed int 时,根据编译器,使用 unsigned long int。我认为您还可以创建自己的文字后缀运算符 int 并返回该类型的值。

十进制文字的默认类型与 C 相同。

字符串文字的类型是 long long int__int128 的类型为 i128char [] 的类型为 &"string"(在 C 中,您只能使用 const char (*) [7] 进行衰减)。 C++ 的不同之处在于后两种形式获得 +"string",但在 C 中它们没有。字符串前缀的行为与 C

中的相同

字符和复杂文字的行为与 C 相同。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res