pow 函数中发生了什么?

2023-12-22

我在这里看到了各种描述奇怪行为的答案powC 中的函数。
但我在这里有一些不同的问题要问。

在下面的代码中我已经初始化了int x = pow(10,2) and int y = pow(10,n) (int n = 2).

在第一种情况下,当我打印它显示的结果时100在另一种情况下,结果是99.

我知道pow回报double它在存储时被截断int,但我想问为什么输出会不同。

CODE1

#include<stdio.h>
#include<math.h>
int main()
{
     int n = 2;
     int x;
     int y;
     x = pow(10,2);   //Printing Gives Output 100   
     y = pow(10,n);   //Printing Gives Output 99


     printf("%d %d" , x , y);

}

Output : 100 99

为什么输出结果不同。 ?

我的gcc版本是4.9.2

Update :

Code 2

int main()
    {
         int n = 2;
         int x;
         int y;
         x = pow(10,2);   //Printing Gives Output 100   
         y = pow(10,n);   //Printing Gives Output 99
         double k = pow(10,2);
         double l = pow(10,n);


         printf("%d %d\n" , x , y);
         printf("%f %f\n" , k , l);

    }

输出 :100 99
100.000000 100.000000

Update 2组装说明 适用于CODE1

生成的组装指令海湾合作委员会4.9.2 using gcc -S -masm=intel :

    .LC1:
    .ascii "%d %d\0"
    .text
    .globl  _main
    .def    _main;  .scl    2;  .type   32; .endef
_main:
    push    ebp
    mov ebp, esp
    and esp, -16
    sub esp, 48
    call    ___main
    mov DWORD PTR [esp+44], 2
    mov DWORD PTR [esp+40], 100      //Concerned Line
    fild    DWORD PTR [esp+44]
    fstp    QWORD PTR [esp+8]
    fld QWORD PTR LC0
    fstp    QWORD PTR [esp]
    call    _pow                    //Concerned Line
    fnstcw  WORD PTR [esp+30]
    movzx   eax, WORD PTR [esp+30]
    mov ah, 12
    mov WORD PTR [esp+28], ax
    fldcw   WORD PTR [esp+28]
    fistp   DWORD PTR [esp+36]
    fldcw   WORD PTR [esp+30]
    mov eax, DWORD PTR [esp+36]
    mov DWORD PTR [esp+8], eax
    mov eax, DWORD PTR [esp+40]
    mov DWORD PTR [esp+4], eax
    mov DWORD PTR [esp], OFFSET FLAT:LC1
    call    _printf
    leave
    ret
    .section .rdata,"dr"
    .align 8
LC0:
    .long   0
    .long   1076101120
    .ident  "GCC: (tdm-1) 4.9.2"
    .def    _pow;   .scl    2;  .type   32; .endef
    .def    _printf;    .scl    2;  .type   32; .endef

我知道 pow 返回 double 并且在存储为 int 时会被截断,但我想问为什么输出会有所不同。

如果您还没有的话,您必须首先放弃浮点数在任何方面都是合理或可预测的想法。double only 近似实数以及几乎任何你用 a 做的事情double很可能是实际结果的近似值。

也就是说,正如你所意识到的,pow(10, n)结果是这样的值99.99999999999997,这是精确到 15 位有效数字的近似值。然后你告诉它截断为小于该值的最大整数,因此它丢弃了其中的大部分。

(旁白:很少有good转换的原因double to an int。通常您应该将其格式化为显示格式,例如sprintf("%.0f", x),它可以正确舍入,或者使用floor函数,它可以处理可能超出范围的浮点数int。如果这些都不适合您的目的,例如在货币或日期计算中,您可能根本不应该使用浮点数。)

这里发生了两件奇怪的事情。第一的,why is pow(10, n)不准确?10、2 和 100 都可以精确表示为double。我能提供的最好答案是您正在使用的 C 标准库有一个错误。 (编译器和标准库,我假设是 gcc 和 glibc,是根据不同的发布计划和由不同的团队开发的。如果pow返回不准确的结果,这可能是 glibc 中的错误,而不是 gcc 中的错误。)

在你的问题的评论中,发现了一个与 FP 舍入有关的 glibc bug https://sourceware.org/bugzilla/show_bug.cgi?id=3976这可能相关并且另一个问答 https://stackoverflow.com/questions/32353301/will-intpown-m-be-wrong-for-some-positive-integers-n-m更详细地说明了为什么会发生这种情况以及它如何不违反 C 标准。 chux的回答也解决了这个问题。 (C 不需要实现IEEE 754 https://en.wikipedia.org/wiki/IEEE_floating_point,但即使这样做了,pow不需要使用正确的舍入。)我仍然将其称为 glibc bug,因为它是一个不受欢迎的属性。

(也可以想象,尽管不太可能,您的处理器的 FPU 是错误的。)

Second, why is pow(10, n)不同于pow(10, 2)?这个要容易得多。 gcc 优化了可以在编译时计算结果的函数调用,因此pow(10, 2)几乎可以肯定正在优化100.0。如果你查看生成的汇编代码,你会发现只有一次调用pow.

The GCC 手册,第 6.59 节 https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#Other-Builtins描述了哪些标准库函数可以以这种方式处理(点击链接查看完整列表):

其余功能是出于优化目的而提供的。

除了具有库等效项(例如下面讨论的标准 C 库函数)或扩展为库调用的内置函数之外,GCC 内置函数始终内联扩展,因此没有相应的入口点,并且它们的地址不能被获得。尝试在函数调用以外的表达式中使用它们会导致编译时错误。

[...]

ISO C90 函数 abort、abs、acos、asin、atan2、atan、calloc、ceil、cosh、cos、exit、exp、fabs、floor、fmod、fprintf、fputs、frexp、fscanf、isalnum、isalpha、iscntrl、isdigit、 isgraph、islower、isprint、ispunct、isspace、isupper、isxdigit、tolower、toupper、实验室、ldexp、log10、日志、malloc、memchr、memcmp、memcpy、memset、modf、pow、 printf、putchar、puts、scanf、sinh、sin、snprintf、sprintf、sqrt、sscanf、strcat、strchr、strcmp、strcpy、strcspn、strlen、strncat、strncmp、strncpy、strpbrk、strrchr、strspn、strstr、tanh、tan 、vfprintf、vprintf 和 vsprintf都被识别为内置函数 unless -fno-builtin已指定(或-fno-builtin-function是为单个函数指定的)。

所以看来你可以禁用这种行为-fno-builtin-pow.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

pow 函数中发生了什么? 的相关文章

  • 如何在另一个应用程序中挂钩 api 调用

    我正在尝试挂钩另一个应用程序的 ExtTextOut 和 DrawTextExt GDI 方法调用 我知道我需要使用 GetProcAddress 来查找 gdi32 dll 中那些方法的地址 并用我的函数的地址覆盖我想要挂钩的进程中的地址
  • 在 Java 中创建 T 的新实例

    在C 中 我们可以定义一个泛型class A
  • C++ 长 switch 语句还是用地图查找?

    在我的 C 应用程序中 我有一些值充当代表其他值的代码 为了翻译代码 我一直在争论使用 switch 语句还是 stl 映射 开关看起来像这样 int code int value switch code case 1 value 10 b
  • 解析 JWT 令牌以仅获取有效负载内容,无需 C# 或 Blazor 中的外部库

    我正在使用 Blazor 编写可以访问 JWT 的客户端应用程序 我想知道一种简单的方法来读取令牌有效负载内容而不添加额外的依赖项 因为我不需要其他信息 也不需要验证令牌 我认为解析有效负载内容应该足够简单 只需将其写入方法即可 JwtTo
  • 在 C# 中调用 C++ 库 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我有很多用 C 编写的库 我想从 C 调用这些库 但是 我遇到了很多问题 我想知道是否有书籍或指南告诉我如何做到这一点 Dll导入 htt
  • 是否存在指向不同类型的指针具有不同大小的平台?

    C 标准允许指向不同类型的指针具有不同的大小 例如sizeof char sizeof int 是允许的 但是 它确实要求如果将指针转换为void 然后转换回其原始类型 它必须与其原始值进行比较 因此 从逻辑上来说 sizeof void
  • 为什么'enable_if'不能用于禁用这里声明

    include
  • C# 开源 NMEA 解析器 [已关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找 C 开源 NMEA 解析器 嗯 我自己也不熟悉 但是一些快速搜索显示了一个代码项目 htt
  • 将表(行)与 OpenXML SDK 2.5 保持在一起

    我想在 Word 文档中生成多个表 每行 2 行 但我想将这两行保留在一起 如果可能的话 new KeepNext 第一行不起作用 new KeepNext 第一行的最后一段不起作用 new CantSplit 放在桌子上不起作用 在所有情
  • 将接口转换为其具体实现对象,反之亦然?

    在 C 中 当我有一个接口和几个具体实现时 我可以将接口强制转换为具体类型 还是将具体类型强制转换为接口 这种情况下的规则是什么 Java 和 C 中都允许这两个方向 向下转型需要显式转型 如果对象类型不正确 可能会抛出异常 然而 向上转换
  • 使用 C# 和 wpf 创建类似 Dock 的应用程序

    我需要创建一个与我们购买笔记本电脑时获得的应用程序类似的应用程序 仅当鼠标指针到达窗口顶部时它才可见 那么我怎样才能使用 C 4 0 来做到这一点呢 http www notebookcheck net uploads pics win2
  • C#6 中的长字符串插值行

    我发现 虽然字符串插值在应用于现有代码库的字符串 Format 调用时非常好 但考虑到通常首选的列限制 字符串对于单行来说很快就会变得太长 特别是当被插值的表达式很复杂时 使用格式字符串 您将获得一个可以拆分为多行的变量列表 var str
  • 搜索实体的所有字段

    我正在尝试在客户数据库上实现 多功能框 类型的搜索 其中单个查询应尝试匹配客户的任何属性 这是一些示例数据来说明我想要实现的目标 FirstName LastName PhoneNumber ZipCode Mary Jane 12345
  • 引用/指针失效到底是什么?

    我找不到任何定义指针 引用无效在标准中 我问这个问题是因为我刚刚发现 C 11 禁止字符串的写时复制 COW 据我了解 如果应用了 COW 那么p仍然是一个有效的指针并且r以下命令后的有效参考 std string s abc std st
  • 使用 jQuery 从 ASP.Net JSON 服务获取数据

    我正在尝试调用 Google 地图地理编码 API 从纬度 经度对中获取格式化的地址 然后将其记录到控制台 我正在尝试获取为给定位置返回的第一个 formatted address 项目 我很简单无法从 JSON 中提取该项目 我不知道为什
  • CUDA 8 编译错误 -std=gnu++11

    我正在尝试转换一些代码以使用 CUDA 并且我认为我遇到了兼容性问题 我们使用CMake 这些是我使用的 gcc 和 CUDA 版本 gcc version gcc Ubuntu 5 4 0 6ubuntu1 16 04 5 5 4 0 2
  • 如何调试 .NET 运行时中的内部错误?

    我正在尝试调试一些处理大文件的工作 代码本身works 但 NET 运行时本身会报告零星错误 对于上下文 这里的处理是一个 1 5GB 文件 仅加载到内存中一次 在循环中处理和释放 故意尝试重现此否则不可预测的错误 我的测试片段基本上是 t
  • 如何在 winforms 应用程序的主屏幕显示之前显示欢迎屏幕?

    我想在应用程序启动时加载欢迎屏幕 然后用户单击欢迎屏幕上的按钮 然后关闭欢迎屏幕 最后显示主屏幕 static void Main startup method being called Application EnableVisualSt
  • 通过 Tab 键浏览 XML 文档字段

    In VB NET you can move through the fields in the XML member documentation with the Tab key 这在 C 中不起作用 还有其他方法吗 除了用鼠标将光标放在
  • 如何得知客户端从服务器的下载速度?

    根据客户的下载速度 我想以低质量或高质量显示视频 任何 Javascript 或 C 解决方案都是可以接受的 Thanks 没有任何办法可以确定 您只能测量向客户端发送数据的速度 如果没有来自客户端的任何类型的输入来表明其获取信息的速度 您

随机推荐

  • 删除滚动条但不删除滚动功能[重复]

    这个问题在这里已经有答案了 我知道你可以定义溢出 隐藏 在 HTML 正文上删除滚动条 但我希望仍然能够使用鼠标上的箭头或滚轮滚动 预先感谢您的任何帮助 编辑 感谢您有关悬停滚动条和自定义栏的所有建议 还要感谢您对删除滚动条影响用户体验的所
  • 捆绑包和文件访问

    我已向我的项目添加了一系列文件夹 使用 添加现有文件 选项 这会导致文件夹内容在 Xcode 中显示为蓝色文件夹 以下作品 NSString imageName NSString stringWithFormat File 03 image
  • PowerShell 范围标识符

    我是 PowerShell 新手 试图更好地理解范围 有没有办法从范围内识别范围 某些变量或函数可以给我某种范围名称或范围 Guid 或范围 Id 例如 我如何知道本地范围是否是全局范围 例如 我如何知道本地范围是否是全局范围 bool i
  • 如何验证传递给“PrincipalContext”的凭据

    这是后续我之前的问题 https stackoverflow com questions 50055073 testing a principalcontext using validatecredentialsnull null beha
  • ant 的 componentdef 错误

    我有一个相对较旧的 Grails 应用程序 它使用 ant 来构建应用程序 在测试服务器中 它构建没有任何问题 但是当我尝试在我的电脑上运行它时 我收到一致的错误 Caused by jar file C ant apache ant 1
  • Scala:理解参数多态性

    有什么区别 def drop1 A l List A l tail and def drop1 l List Int l tail 假设用法看起来像 drop1 List 1 2 3 何时应该使用其中之一 为什么 虽然我可以理解第二个例子
  • Swift“文本”不可用:自 iOS7 起已弃用 API。文本标签不起作用

    我一直有这个错误 我已经看到使用 textLabel text 回答了其他问题 但它在我的情况下不起作用 我是 swift 的新手 所以有人可以解释一下为什么以及如何解决这个问题 你需要打开包装textLabel通过使用 after tex
  • 将可变 Arc 引用传递给 hyper service_fn 处理程序时出现问题

    我一直在尝试以下 显示相关导入和代码 use std sync Arc Mutex use std thread use hyper rt self Future Stream use hyper service service fn us
  • 设置图例符号不透明度

    我正在绘制带有半透明 x 标记 20 alpha 的绘图 如何使图例中的标记以 100 不透明度显示 import matplotlib pyplot as plt plt plot date x xaxis y yaxis marker
  • C# 代码片段和汇编 TBB 有什么区别?

    据我了解 C 代码片段和 NET 程序集为模块化模板开发提供相同的功能 我们在 CME 中管理代码片段 在 Visual Studio 中管理汇编代码 但在模板生成器中使用相同的方式 在代码方面 我可以创建一个C 代码片段模板构建块 TBB
  • 更改 XSL 转换中的命名空间值?

    我不确定这是否可能 因为我对 XSLT 之类的东西非常陌生 但也许你们中的一些人可以在这里帮助我 这有点棘手 我在互联网上没有找到类似的东西 问题是我有一个输入 xml 其中声明了名称空间和所有内容 我只需要对其进行轻微更改 添加或删除属性
  • Django 静态文件应用程序帮助

    我对 Django 有一个小问题静态文件应用程序 https docs djangoproject com en dev ref contrib staticfiles 我已经添加了 django contrib staticfiles 到
  • React.js - Flux 与全局事件总线

    与全局事件总线相比 使用 Flux 有何优势 我认为调度程序就是所需要的 组件将带有数据的 用户事件 发布到调度程序 调度程序执行订阅商店的处理程序 处理程序发布 更新事件 以及商店的更新属性 调度程序执行订阅组件的处理程序 并使用存储的更
  • 在 python 中将 RAW 图像转换为 TIFF 但保留元数据

    我尝试将原始图像转换为 tiff 但我希望它保留元数据 这是我之前使用的代码 import rawpy imageio os with rawpy imread path as raw rgb raw postprocess imageio
  • Python 浮点格式

    我已经看到了一些与此相关的问题 但我读到的这些问题都没有帮助我真正理解为什么我想做的事情失败了 所以我有一堆浮点值 它们有不同的精度 有些是 0 1 其他是 1 759374 等 我想格式化它们 以便它们全部采用我尝试做的 0 000000
  • ilasm / ildasm 的 Java 字节码等效项

    对于 CIL MSIL 我可以在文本编辑器中编写代码并使用 ilasm ildasm 进行编译 反编译 我可以使用 Reflector 来查看 NET 类生成的 CIL 在Java世界中 javap c显示反汇编的字节代码 如何编译 Jav
  • 保存和删除 NSManagedObject 和 NSManagedObjectContext

    三个问题 但它们都是相关的 如果您愿意 我可以将它们分为三个问题 以便您获得更多学分 如果您愿意我这样做 请告诉我 我有以下代码允许我访问 NSManagedObject self managedObjectContext STAppDel
  • 使用 ipdb 默认进入粘性模式

    调试时使用ipdb 我发现输入很有用sticky模式遵循代码源 有没有办法在粘滞模式下自动输入而无需输入sticky 是的 从REAMDE https github com mverteuil pdbpp configuration and
  • 在 XAML 中为一个事件添加多个事件处理程序?

    在程序代码中可以执行以下操作 Add two event handler for the button click event button1 Click new RoutedEventHandler button1 Click 1 but
  • pow 函数中发生了什么?

    我在这里看到了各种描述奇怪行为的答案powC 中的函数 但我在这里有一些不同的问题要问 在下面的代码中我已经初始化了int x pow 10 2 and int y pow 10 n int n 2 在第一种情况下 当我打印它显示的结果时1