2016 - 2024

感恩一路有你

java浮点数运算不精确的原因 float和double区别?

浏览量:2757 时间:2023-06-11 09:15:20 作者:采采

float和double区别?

浮动的解释:

动词 (verb的缩写)飘,飘;漂泊,飘动;漂移;安排(贷款)被提出来考虑(一个想法或计划);发行(股票)上市;自由浮动(货币汇率)

零钱(用于酒吧等给顾客找钱);飘,飘;浮板;漂浮物;鱼漂;浮动;冰淇淋饮料;浮动期;坐在漂浮的盒子里(为了治疗、康复或放松);救生圈

双重解释:

双倍;配对;(指花)有重瓣的;对于两个人来说;两倍

非常相似的对应物;身体替身;两个人的东西;双倍;(复数)双打,尤指网球;双料冠军(同一赛季或同一年度两次夺冠者);(棒球)双重打击;双精度浮点数(在C语言中)

动词 (v

Java和C# 最大的不同是什么?

我觉得除了语法,最重要的是对底层的掌控能力不同。

虽然C#一开始借鉴了Java,但其目的根本不是为了构建一个更好的Java,而是为了构建一个更好的C,游戏引擎更喜欢C#就是这个原因。

例如,在C#中可以做什么:

上面的代码会输出10,为什么?因为数组的长度。NET存储在数组第一个元素之前的8字节内存中。如果您随后输出*(long *)p-2),您将直接获得该对象的TypeHandle地址:

然后拿着这个指针,就可以访问对象的MethodTable了。

此外,您可以在堆栈上手动分配空间:

然后,您希望绕过GC,直接手动分配堆内存:

以上调用相当于C语言中你调用的malloc,此外还有AllocAligned,Realloc,AllocZeroed等等,可以直接控制内存对齐。

接下来,您希望创建一个具有显式内存布局的结构Foo:

那么你就成功模拟了C的一个并集,之所以会有上面的输出,是因为单精度浮点数1的二进制表示是0x 01111111000000000000000000000000,在小终端模式存储后占用了4个字节,分别是0x000000000000、0x 00000000000、0x 000000000。

此外,您可以直接从内存数据构造对象,而无需任何复制开销:

甚至像这样:

从堆内存中创建自然很好:

再比如,此时你有一个用C写的库,里面有这样一段代码:

然后我们编写下面的C#代码:

上面的代码做了什么?我们把C#的函数指针传入C代码,然后在C端调用C#函数。数字生成一个字符串wwwww,然后把这个字符串返回给C#端。它不 使用委托而不是函数指针并不重要,因为函数指针在。网。

即使我们没有。;我不想要。NET要导入foo.dll,而我们想自己决定动态库的生命周期,我们也可以写:

以上都不是特定于Windows和导入的。所以还有。Linux和macOS上的dylib是完全不可能的。

此外,我们有一些数据,我们想计算,但我们想使用SIMD进行处理,所以我们只需要写:

您可以看到在X86平台上生成了什么代码:

平台判断的分支会被JIT自动淘汰。但实际上,除了手动编写SIMD代码,前两个分支完全可以省略,只剩下:

因为在这个阶段,当循环边界条件是向量长度时,。NET会自动为我们做定向量化,扩展循环。

然后继续,我们还有ref,in和out来传递引用。

假设我们有一个大的struct,为了避免传递时的复制,我们可以直接使用in进行只读引用传递:

对于小型结构,为。NET有特殊的优化来帮助我们完全消除内存分配,并将结构完全放在寄存器中,如下面的代码:

上面的代码GetDistance被认为是一个热路径,所以我添加了它来指示JIT有保证地内联这个函数,最后生成了下面的代码进行测试:

整个过程没有访问内存的指令,效率非常高。

我们也可以借用ref的引用语义来做就地更新:

它甚至可以用于指针和手动分配内存:

与Java不同,C#中的泛型真正专门化了所有的类型参数(虽然运行时分布用于引用类型的共享实现),这意味着性能可以得到最大程度的保证,对应的类型根据类型参数的大小有专门的内存布局。还是上面的点例子,我们将下面的数据int替换为泛型参数t,并对值类型number进行泛型约束:

无论是Test1还是Test2,生成的代码都很优秀,不仅没有打包和解包,而且没有访问操作:

然后,我们有时为了高性能想暂时中止GC恢复,就一句简单的话:

如果你还能分配128mb的内存,你可以告诉GC不要回收,然后一段时间后,即使我们在这个预算中分配内存,也不会发生GC。它甚至可以防止在内存分配不足时阻塞完全垃圾收集:

代码执行完毕,最后一次调用a:

可以恢复。GC行为。

此外,我们还可以指定GC在运行时的模式,以最大限度地提高性能:

此外,我们甚至可以直接在堆内存中执行代码,创建一个JIT。NET中,直接从内存中创建一个可执行区,然后在其中插入一段代码来添加两个32位整数:

除此之外,C#还有无数底层的编写方法与操作系统交互,甚至使用C#的编译器解除与自身标准库的链接,直接从0开始构建基本类型,然后通过NativeAOT编译出完全无GC、可以在裸机硬件上执行引导系统的EFI固件也是没有问题的。

另外还有ILGPU可以让你直接在GPU上运行C#代码,在嵌入式设备上运行可以直接操作I2C、PWM、GPIO等。,所以不再举例。

而C#已经进入了roadmap的后续更新:允许引用字段的声明,增加类型表示定长内存,允许传递数组时消除数组分配,允许栈上任何对象的分配等等。,所有这些都在改善这些基础性能设施。

那个 这是我认为C#和Java最大的区别。

在C#中,当你不 t需要这些东西,它们好像从来不存在,允许动态类型,不断吸收各种功能特性,各种语法糖加持。简单性和灵活性。;甚至不会失去Python,所以你可以愉快而简单地编写各种代码。一旦你需要,你就可以拥有从上到下几乎完全的控制能力,而这些能力会让你在必要的时候不用思考各种奇怪的变通方法,直接把机器榨干,达到C和C的性能,甚至因为运行时PGO而超过C和C的性能。

内存 代码 类型

版权声明:本文内容由互联网用户自发贡献,本站不承担相关法律责任.如有侵权/违法内容,本站将立刻删除。