- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在阅读 Michael Abrash 的 Graphics Programming Black Book,它是关于 3D 图形性能的,所以我惊讶地发现那里的很多 C 代码都使用了 double
而不是 float
.我们谈论的是 90 年代早期的计算机(286、386、奔腾)和 MS-DOS C 编译器,那么使用 double
的原因是什么?在那个时代?没有float
存在或曾经 double
的和 float
的精度与今天不同吗?
总之,为什么double
在那个时代被用于性能关键代码?
最佳答案
据我所知,没有针对 MS-DOS 的 C 编译器使用 32 位宽 double
,相反,他们都使用了 64 位宽 double
.到 90 年代初,情况确实如此。基于对本书“实时 3D 浮点”一章的快速阅读,Michael Abrash 似乎认为任何精度的浮点数学在低于 Pentium CPU 的任何东西上都太慢了。您正在寻找的浮点代码要么是为奔腾 CPU 设计的,要么是用于性能无关紧要的非关键路径。对于适用于早期 CPU 的性能关键代码,Abrash 暗示他会使用定点算法来代替。
在很多情况下使用 float
而不是 double
实际上不会有太大的不同。有几个原因。首先,如果您没有 x87 FPU (floating-point unit)安装('486 之前的单独芯片),使用较低的精度不会提高性能足以使软件模拟浮点算法足够快以用于游戏。第二个是大多数 x87 FPU 操作的性能实际上不受精度影响。在 Pentium CPU 上,如果以较窄的精度执行,则只有除法会更快。对于早期的 x87 FPU,我不确定精度会影响除法,但它可能会影响 80387 上的乘法性能。在所有 x87 FPU 上,无论精度如何,加法的速度都是相同的。
第三是具体使用的C数据类型,是否是32位float
, 64 位 double
,甚至 80 位 long double
许多编译器支持,实际上并没有影响 FPU 在计算过程中使用的精度。这是因为 FPU 对于它支持的三种不同精度没有不同的指令(或编码)。没有办法告诉它执行 float
添加或 double
划分。相反,它以 FPU 控制寄存器中设置的给定精度执行所有算术运算。 (或者更准确地说,它执行算术就像使用无限精度然后将结果四舍五入到设置精度。)虽然每次使用浮点指令时都可以更改此寄存器,但这会导致大量性能下降,所以编译器从来没有这样做过。相反,他们只是在程序启动时将其设置为 80 位或 64 位精度,然后保持这种方式。
现在,将 FPU 设置为单精度实际上是 3D 游戏的常用技术。这意味着浮点运算,无论是否使用 double
或 float
类型,将使用单精度算术执行。虽然这最终只会影响浮点除法的性能,但 3D 图形编程往往会在关键代码(例如透视除法)中进行大量除法,因此这可能会显着提高性能。
然而,有一种方法可以使用 float
而不是 double
可以提高性能,这仅仅是因为 float
占用double
的一半空间.如果您有很多浮点值,那么必须读写一半的内存会对性能产生显着影响。但是,在 Pentium 或更早的 PC 上,这不会导致今天的巨大性能差异。那时 CPU 速度和 RAM 速度之间的差距并没有那么大,浮点性能要慢一些。尽管如此,如果不需要额外的精度,这将是值得的优化,这在游戏中通常是这种情况。
请注意,现代 x86 C 编译器通常不使用 x87 FPU 指令进行浮点运算,而是使用标量 SSE 指令,与 x87 指令不同,它有单精度和 double 版本。 (但没有 80 位宽的扩展精度版本。)除了除法之外,这不会产生任何性能差异,但确实意味着结果总是被截断为 float
或 double
每次操作后的精度。在 x87 FPU 上进行数学运算时,这种截断只会在结果写入内存时发生。这意味着 SSE 浮点代码现在具有可预测的结果,而 x87 FPU 代码具有不可预测的结果,因为通常很难预测编译器何时需要将浮点寄存器溢出到内存中以便为其他内容腾出空间。
所以基本上使用 float
而不是 double
除非将浮点值存储在内存中的大数组或其他大型数据结构中,否则不会产生很大的性能差异。
关于c - 旧的 DOS C 编译器是否将 double 实现为 32 位?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59094449/
我有一个 if 语句,如下所示 if (not(fullpath.lower().endswith(".pdf")) or not (fullpath.lower().endswith(tup
然而,在 PHP 中,可以: only appears if $foo is true. only appears if $foo is false. 在 Javascript 中,能否在一个脚
XML有很多好处。它既是机器可读的,也是人类可读的,它具有标准化的格式,并且用途广泛。 它也有一些缺点。它是冗长的,不是传输大量数据的非常有效的方法。 XML最有用的方面之一是模式语言。使用模式,您可
由于长期使用 SQL2000,我并没有真正深入了解公用表表达式。 我给出的答案here (#4025380)和 here (#4018793)违背了潮流,因为他们没有使用 CTE。 我很欣赏它们对于递
我有一个应用程序: void deleteObj(id){ MyObj obj = getObjById(id); if (obj == null) { throw n
我的代码如下。可能我以类似的方式多次使用它,即简单地说,我正在以这种方式管理 session 和事务: List users= null; try{ sess
在开发J2EE Web应用程序时,我通常会按以下方式组织我的包结构 com.jameselsey.. 控制器-控制器/操作转到此处 服务-事务服务类,由控制器调用 域-应用程序使用的我的域类/对象 D
这更多是出于好奇而不是任何重要问题,但我只是想知道 memmove 中的以下片段文档: Copying takes place as if an intermediate buffer were us
路径压缩涉及将根指定为路径上每个节点的新父节点——这可能会降低根的等级,并可能降低路径上所有节点的等级。有办法解决这个问题吗?有必要处理这个吗?或者,也许可以将等级视为树高的上限而不是确切的高度? 谢
我有两个类,A 和 B。A 是 B 的父类,我有一个函数接收指向 A 类型类的指针,检查它是否也是 B 类型,如果是将调用另一个函数,该函数接受一个指向类型 B 的类的指针。当函数调用另一个函数时,我
有没有办法让 valgrind 使用多个处理器? 我正在使用 valgrind 的 callgrind 进行一些瓶颈分析,并注意到我的应用程序中的资源使用行为与在 valgrind/callgrind
假设我们要使用 ReaderT [(a,b)]超过 Maybe monad,然后我们想在列表中进行查找。 现在,一个简单且不常见的方法是: 第一种可能性 find a = ReaderT (looku
我的代码似乎有问题。我需要说的是: if ( $('html').attr('lang').val() == 'fr-FR' ) { // do this } else { // do
根据this文章(2018 年 4 月)AKS 在可用性集中运行时能够跨故障域智能放置 Pod,但尚不考虑更新域。很快就会使用更新域将 Pod 放入 AKS 中吗? 最佳答案 当您设置集群时,它已经自
course | section | type comart2 : bsit201 : lec comart2 :
我正在开发自己的 SDK,而这又依赖于某些第 3 方 SDK。例如 - OkHttp。 我应该将 OkHttp 添加到我的 build.gradle 中,还是让我的 SDK 用户包含它?在这种情况下,
随着 Rust 越来越充实,我对它的兴趣开始激起。我喜欢它支持代数数据类型,尤其是那些匹配的事实,但是对其他功能习语有什么想法吗? 例如标准库中是否有标准过滤器/映射/归约函数的集合,更重要的是,您能
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 关闭 9 年前。 Improve
我一直在研究 PHP 中的对象。我见过的所有示例甚至在它们自己的对象上都使用了对象构造函数。 PHP 会强制您这样做吗?如果是,为什么? 例如: firstname = $firstname;
...比关联数组? 关联数组会占用更多内存吗? $arr = array(1, 1, 1); $arr[10] = 1; $arr[] = 1; // <- index is 11; does the
我是一名优秀的程序员,十分优秀!