为何c语言中64位模运算性能如此反常,竟成编程界的长尾之谜?

2026-04-16 17:103阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计829个文字,预计阅读时间需要4分钟。

为何c语言中64位模运算性能如此反常,竟成编程界的长尾之谜?

这些方法调用的最后三个参数需要较大约定。与前面的四个参数相比,区别在于它们的参数不再适合整数。但这有关联吗?该参数应明确声明为long,因为目前无相关讨论,任何数字计算都应使用long进行。模型运算是否应对数字使用long?

这些方法调用的最后三个需要大约.比前四个时间翻倍.

唯一的区别是它们的参数不再适合整数.但这有关系吗?该参数声明为long,因此无论如何都应该使用long进行计算.模运算是否对数字> maxint使用另一种算法?

我正在使用amd athlon64 3200,winxp sp3和vs2008.

为何c语言中64位模运算性能如此反常,竟成编程界的长尾之谜?

Stopwatch sw = new Stopwatch(); TestLong(sw, int.MaxValue - 3l); TestLong(sw, int.MaxValue - 2l); TestLong(sw, int.MaxValue - 1l); TestLong(sw, int.MaxValue); TestLong(sw, int.MaxValue + 1l); TestLong(sw, int.MaxValue + 2l); TestLong(sw, int.MaxValue + 3l); Console.ReadLine(); static void TestLong(Stopwatch sw, long num) { long n = 0; sw.Reset(); sw.Start(); for (long i = 3; i < 20000000; i++) { n += num % i; } sw.Stop(); Console.WriteLine(sw.Elapsed); }

编辑:
我现在尝试用C进行相同的操作并且此处不会出现此问题,所有模运算都需要同时进行,在发布和调试模式下启用和未启用优化:

#include "stdafx.h" #include "time.h" #include "limits.h" static void TestLong(long long num) { long long n = 0; clock_t t = clock(); for (long long i = 3; i < 20000000LL*100; i++) { n += num % i; } printf("%d - %lld\n", clock()-t, n); } int main() { printf("%i %i %i %i\n\n", sizeof (int), sizeof(long), sizeof(long long), sizeof(void*)); TestLong(3); TestLong(10); TestLong(131); TestLong(INT_MAX - 1L); TestLong(UINT_MAX +1LL); TestLong(INT_MAX + 1LL); TestLong(LLONG_MAX-1LL); getchar(); return 0; }

EDIT2:

谢谢你的好建议.我发现.net和c(在调试和发布模式下)都不会使用原子cpu指令来计算余数,但是它们调用了一个函数.

在c程序中,我可以得到它的名称“_allrem”.它还显示了该文件的完整源代码注释,因此我发现该算法特殊情况下的信息是32位除数而不是.net应用程序中的除数.

我还发现,c程序的性能实际上只受除数的值而不是除数的影响.另一个测试表明,.net程序中余数函数的性能取决于被除数和除数.

顺便说一下:即使简单添加长long值也是通过连续的add和adc指令计算的.所以,即使我的处理器自称64位,它实际上不是:(

EDIT3:

我现在在使用visual studio 2010编译的Windows 7 x64版本上运行了c应用程序.有趣的是,性能行为保持不变,尽管现在(我检查了汇编源代码)使用了真正的64位指令.

多么奇怪的观察.您可以采取以下措施进一步调查:在程序开头添加“暂停”,如Console.ReadLine,但在第一次调用方法之后.然后以“发布”模式构建程序.然后启动程序不在调试器中.然后,在暂停时,附加调试器.通过它进行调试,然后查看为相关方法编写的代码.找到循环体应该很容易.

知道生成的循环体与C程序中的循环体有何不同会很有趣.

所有这些箍跳过的原因是因为抖动会改变它在jitting“debug”程序集时或者在已经附加了调试器的程序时生成的代码.在这些情况下,它会调试在调试器中更容易理解的代码.看看抖动是什么意思是为这种情况生成的“最佳”代码会更有趣,所以你必须在运行抖动之后加入调试器.

本文共计829个文字,预计阅读时间需要4分钟。

为何c语言中64位模运算性能如此反常,竟成编程界的长尾之谜?

这些方法调用的最后三个参数需要较大约定。与前面的四个参数相比,区别在于它们的参数不再适合整数。但这有关联吗?该参数应明确声明为long,因为目前无相关讨论,任何数字计算都应使用long进行。模型运算是否应对数字使用long?

这些方法调用的最后三个需要大约.比前四个时间翻倍.

唯一的区别是它们的参数不再适合整数.但这有关系吗?该参数声明为long,因此无论如何都应该使用long进行计算.模运算是否对数字> maxint使用另一种算法?

我正在使用amd athlon64 3200,winxp sp3和vs2008.

为何c语言中64位模运算性能如此反常,竟成编程界的长尾之谜?

Stopwatch sw = new Stopwatch(); TestLong(sw, int.MaxValue - 3l); TestLong(sw, int.MaxValue - 2l); TestLong(sw, int.MaxValue - 1l); TestLong(sw, int.MaxValue); TestLong(sw, int.MaxValue + 1l); TestLong(sw, int.MaxValue + 2l); TestLong(sw, int.MaxValue + 3l); Console.ReadLine(); static void TestLong(Stopwatch sw, long num) { long n = 0; sw.Reset(); sw.Start(); for (long i = 3; i < 20000000; i++) { n += num % i; } sw.Stop(); Console.WriteLine(sw.Elapsed); }

编辑:
我现在尝试用C进行相同的操作并且此处不会出现此问题,所有模运算都需要同时进行,在发布和调试模式下启用和未启用优化:

#include "stdafx.h" #include "time.h" #include "limits.h" static void TestLong(long long num) { long long n = 0; clock_t t = clock(); for (long long i = 3; i < 20000000LL*100; i++) { n += num % i; } printf("%d - %lld\n", clock()-t, n); } int main() { printf("%i %i %i %i\n\n", sizeof (int), sizeof(long), sizeof(long long), sizeof(void*)); TestLong(3); TestLong(10); TestLong(131); TestLong(INT_MAX - 1L); TestLong(UINT_MAX +1LL); TestLong(INT_MAX + 1LL); TestLong(LLONG_MAX-1LL); getchar(); return 0; }

EDIT2:

谢谢你的好建议.我发现.net和c(在调试和发布模式下)都不会使用原子cpu指令来计算余数,但是它们调用了一个函数.

在c程序中,我可以得到它的名称“_allrem”.它还显示了该文件的完整源代码注释,因此我发现该算法特殊情况下的信息是32位除数而不是.net应用程序中的除数.

我还发现,c程序的性能实际上只受除数的值而不是除数的影响.另一个测试表明,.net程序中余数函数的性能取决于被除数和除数.

顺便说一下:即使简单添加长long值也是通过连续的add和adc指令计算的.所以,即使我的处理器自称64位,它实际上不是:(

EDIT3:

我现在在使用visual studio 2010编译的Windows 7 x64版本上运行了c应用程序.有趣的是,性能行为保持不变,尽管现在(我检查了汇编源代码)使用了真正的64位指令.

多么奇怪的观察.您可以采取以下措施进一步调查:在程序开头添加“暂停”,如Console.ReadLine,但在第一次调用方法之后.然后以“发布”模式构建程序.然后启动程序不在调试器中.然后,在暂停时,附加调试器.通过它进行调试,然后查看为相关方法编写的代码.找到循环体应该很容易.

知道生成的循环体与C程序中的循环体有何不同会很有趣.

所有这些箍跳过的原因是因为抖动会改变它在jitting“debug”程序集时或者在已经附加了调试器的程序时生成的代码.在这些情况下,它会调试在调试器中更容易理解的代码.看看抖动是什么意思是为这种情况生成的“最佳”代码会更有趣,所以你必须在运行抖动之后加入调试器.