首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > C# >

大家来看看运算符的效率,怎么快速求uint抹去低16位之后的值

2012-02-28 
大家来看看运算符的效率,如何快速求uint抹去低16位之后的值C# codelong l1 DateTime.Now.Ticksfor (int

大家来看看运算符的效率,如何快速求uint抹去低16位之后的值

C# code
            long l1 = DateTime.Now.Ticks;            for (int i = 0; i < 100000000; i++)            {                uint x = 0xffffaaaa & 0xffff0000;            }            TimeSpan ts = new TimeSpan(DateTime.Now.Ticks - l1);            long l2 = DateTime.Now.Ticks;            for (int i = 0; i < 100000000; i++)            {                uint x = (0xffffaaaa >> 16 << 16);            }            TimeSpan ts2 = new TimeSpan(DateTime.Now.Ticks - l2);            long l3 = DateTime.Now.Ticks;            unchecked            {                for (int i = 0; i < 100000000; i++)                {                    uint x = (0xffffaaaa - (ushort)(0xffffffff));                }            }            TimeSpan ts3 = new TimeSpan(DateTime.Now.Ticks - l3);            long l4 = DateTime.Now.Ticks;            unsafe            {                uint test = 0xffffaaaa;                for (int i = 0; i < 100000000; i++)                {                    //uint x = ((uint)(*(((ushort*)(&(test)))+1))) << 16 ;                    uint x = ((uint)(*(((ushort*)(&(test)))+1))) * 65535 ;                }            }            TimeSpan ts4 = new TimeSpan(DateTime.Now.Ticks - l4);            long l5 = DateTime.Now.Ticks;            unsafe            {                uint test = 0xffffaaaa;                for (int i = 0; i < 100000000; i++)                {                    *((ushort*)(&(test))) = 0;                    uint x = test;                }            }            TimeSpan ts5 = new TimeSpan(DateTime.Now.Ticks - l5);            Console.WriteLine("1:" + ts.Ticks + "\r\n2:" + ts2.Ticks + "\r\n3:" + ts3.Ticks + "\r\n4:" + ts4.Ticks + "\r\n5:" + ts5.Ticks);



代码贴上. 几种可以求uint抹去低16位之后的值的方法. 大家有更高效率的话可以补充.

大家先别去试,先猜想一下应该哪个最快,然后再去试.



[解决办法]
整数加减最快
整数移位、位运算其次
整数乘除再其次

(2)最快。
[解决办法]
来一个并行加快的:

C# code
            //using System.Threading.Tasks;            Parallel.For(0, 9, pos =>            {                for (int i = 0; i < 10000000; i++)                {                    uint x = (0xffffaaaa >> 16 << 16);                }            });
[解决办法]
。。。跑了下123一样快。。。

但是并行显然更快:

1:2656250
2:2656250
3:2656250
4:3125000
5:7187500
6:1406250

C# code
using System;using System.Runtime.InteropServices;using System.Collections.Generic;using System.Threading.Tasks;using System.Linq;using System.Text;namespace ConsoleApplication1{    class Program    {        static void Main(string[] args)        {            long l1 = DateTime.Now.Ticks;            for (int i = 0; i < 100000000; i++)            {                uint x = 0xffffaaaa & 0xffff0000;            }            TimeSpan ts = new TimeSpan(DateTime.Now.Ticks - l1);            long l2 = DateTime.Now.Ticks;            for (int i = 0; i < 100000000; i++)            {                uint x = (0xffffaaaa >> 16 << 16);            }            TimeSpan ts2 = new TimeSpan(DateTime.Now.Ticks - l2);            long l3 = DateTime.Now.Ticks;            unchecked            {                for (int i = 0; i < 100000000; i++)                {                    uint x = (0xffffaaaa - (ushort)(0xffffffff));                }            }            TimeSpan ts3 = new TimeSpan(DateTime.Now.Ticks - l3);            long l4 = DateTime.Now.Ticks;            unsafe            {                uint test = 0xffffaaaa;                for (int i = 0; i < 100000000; i++)                {                    //uint x = ((uint)(*(((ushort*)(&(test)))+1))) << 16 ;                    uint x = ((uint)(*(((ushort*)(&(test))) + 1))) * 65535;                }            }            TimeSpan ts4 = new TimeSpan(DateTime.Now.Ticks - l4);            long l5 = DateTime.Now.Ticks;            unsafe            {                uint test = 0xffffaaaa;                for (int i = 0; i < 100000000; i++)                {                    *((ushort*)(&(test))) = 0;                    uint x = test;                }            }            TimeSpan ts5 = new TimeSpan(DateTime.Now.Ticks - l5);            long l6 = DateTime.Now.Ticks;            Parallel.For(0, 9, pos =>            {                for (int i = 0; i < 10000000; i++)                {                    uint x = (0xffffaaaa >> 16 << 16);                }            });            TimeSpan ts6 = new TimeSpan(DateTime.Now.Ticks - l6);            Console.WriteLine("1:" + ts.Ticks + "\r\n2:" + ts2.Ticks + "\r\n3:" + ts3.Ticks + "\r\n4:" + ts4.Ticks + "\r\n5:" + ts5.Ticks + "\r\n6:" + ts6.Ticks);        }    }} 


[解决办法]

探讨
在我这里 怎么跑 都是2最快.
win7系统 + intel i5 430CPU

[解决办法]
3 楼误人子弟啊!
想法很好,可惜测试结果是最慢的!
 Parallel.For(0, 9, pos =>
{
for (int i = 0; i < 10000000; i++)
{
uint x = (0xffffaaaa >> 16 << 16);
}
});
循环代码中的位数比前面的少一个0,导致结果快了10倍,实际上它是最慢的。

可以分析一下,用并行循环思路很好,可惜CPU还要处理并行算法和锁,导致结果变慢
这种并行算法实用于复杂算法,对简单运算反而会变慢。
[解决办法]
探讨
3 楼误人子弟啊!
想法很好,可惜测试结果是最慢的!
Parallel.For(0, 9, pos =>
{
for (int i = 0; i < 10000000; i++)
{
uint x = (0xffffaaaa >> 16 << 16);
}
});
循环代码中的位数比前面的少一个0,导致结果快了10倍,实际上它是最慢的。

可以分析一……

[解决办法]
对不起,可能我没有完全掌握Parallel.For的用法,
但MSDN上说明或许可以参考一下: 
当 For()循环的循环体很小时,它的执行速度可能比等效的顺序循环更慢。 对数据进行分区所涉及的开销以及调用每个循环迭代上的委托的开销导致了性能降低。为了解决类似情况, Partitioner 类提供 Create 方法,该方法使您可以为委托体提供顺序循环,以便每个分区只调用一次委托,而不是每个迭代调用一次委托
[解决办法]
探讨
对不起,可能我没有完全掌握Parallel.For的用法,
但MSDN上说明或许可以参考一下:
当 For()循环的循环体很小时,它的执行速度可能比等效的顺序循环更慢。 对数据进行分区所涉及的开销以及调用每个循环迭代上的委托的开销导致了性能降低。为了解决类似情况, Partitioner 类提供 Create 方法,该方法使您可以为委托体提供顺序循环,以便每个分区只调用一次委托,而不是每个迭……

[解决办法]
lz给出的是一个特例,因为循环内部没有使用循环变量,也不涉及内存访问。

否则要考虑存储器连续性的问题。
[解决办法]
uint x = (0xffffaaaa >> 16 << 16);
移位运算应该是快的
[解决办法]
这个实际上并没有节约CPU时间,只不过让CPU的核心分担时间罢了

还不如起CPU核心数量的线程,分份做

不过也没什么意义。因为实际处理每次的截取uint后2位并没有加快

问题的关键是每次运算的时间更短

循环那么多次只是为了便于比较时间

探讨
来一个并行加快的:


C# code

//using System.Threading.Tasks;
Parallel.For(0, 9, pos =>
{
for (int i = 0; i < 10000000; i++)
{
……

[解决办法]
探讨
这个实际上并没有节约CPU时间,只不过让CPU的核心分担时间罢了

还不如起CPU核心数量的线程,分份做

不过也没什么意义。因为实际处理每次的截取uint后2位并没有加快

问题的关键是每次运算的时间更短

循环那么多次只是为了便于比较时间


引用:
来一个并行加快的:


C# code

//using System.Thre……

[解决办法]
你还是在考虑这个截取操作执行100000000次的问题

问题不是100000000次

而是执行一次的时间消耗

让他执行100000000次只不过是让时间更具有可比性

另外,我有一种截取方法

C# code
                uint test = 0xffffaaaa;                for (int i = 0; i < 100000000; i++)                {                    *((ushort*)(&test)) = 0;                }
[解决办法]
而且就测试的结果来看,就让程序在一个核心上跑,你的代码也不快
[解决办法]
1:6406250
2:6562500
3:6718750
4:6406250
5:5937500 Parallel 单核心
请按任意键继续. . .

好像确实是快一点啊

睡觉了,版主,咱明天再说
------解决方案--------------------


探讨
1:6406250
2:6562500
3:6718750
4:6406250
5:5937500 Parallel 单核心
请按任意键继续. . .

好像确实是快一点啊

睡觉了,版主,咱明天再说

[解决办法]
整数加减最快
整数移位、位运算其次
整数乘除再其次

[解决办法]
专业!!!!!!!!!!!!!!!!!1111
[解决办法]
探讨
整数加减最快
整数移位、位运算其次
整数乘除再其次

[解决办法]
来一个 Intel Pentium 4 2.40C w/ Hyper-Threading Technology 的成绩:
1:5312500
2:5468750
3:5000000
4:6093750
5:27812500
6:3750000

打开优化:
1:781250
2:625000
3:937500
4:781250
5:1250000
6:625000
[解决办法]
非常遗憾地告诉lz,你的程序是错的。。。

算法3和算法4求出来的值不正确。(1)(2)(3)我觉得几乎是等价的,理论上一样快。
[解决办法]
算法1~6分别如下:
4294901760 
4294901760 
4294879915 
4294836225 
4294901760 
4294901760
[解决办法]
马克一下 很有趣的东西
[解决办法]
并行显然更快
[解决办法]
做了很多测试
下面是部分测试结果
让每种方法执行三次500000000次循环
测试都将进程的优先级调整到最高,并且限定在单核心上
Assembly code
Debug 单核心33593750    :*((ushort*)(&test)) = 032656250    :*((ushort*)(&test)) = 032968750    :*((ushort*)(&test)) = 032500000    :test = test & 0xffff000032968750    :test = test & 0xffff0000;32656250    :test = test & 0xffff0000;42656250    :test = test >> 16 << 1642656250    :test = test >> 16 << 1642343750    :test = test >> 16 << 1632656250    :test = 0xffff000032968750    :test = 0xffff000032968750    :test = 0xffff000038281250    :Parallel: test1 = test1 & 0xffff000038125000    :Parallel: test1 = test1 & 0xffff000038281250    :Parallel: test1 = test1 & 0xffff0000请按任意键继续. . .Release 单核心11562500    :*((ushort*)(&test)) = 013437500    :*((ushort*)(&test)) = 09843750     :*((ushort*)(&test)) = 09843750     :test = test & 0xffff00006718750     :test = test & 0xffff0000;13281250    :test = test & 0xffff0000;7343750     :test = test >> 16 << 1613281250    :test = test >> 16 << 166718750     :test = test >> 16 << 1610000000    :test = 0xffff00006718750     :test = 0xffff00006718750     :test = 0xffff00009218750     :Parallel: test1 = test1 & 0xffff00009062500     :Parallel: test1 = test1 & 0xffff00008906250     :Parallel: test1 = test1 & 0xffff0000请按任意键继续. . .
[解决办法]
各位都好厉害啊
[解决办法]
to 18#

你这样是用的格式转换。
而事实上CPU最恨你用比它的寄存器小的大小来操作数据,比方带16bits寄存器的一句指令要比正常的32bits寄存器的指令慢10倍。

但为什么不就这样最简单有效呢:
short temp_shortI= In_Dw& 0xffff0000;
只有一个寄存器指令,改善成这样可以提高一些效率 /:^]:


unsigned int Buffer_UIarry[100000000] = {0xffffaaaa};
//这儿先判断要处理的数量能不能被6整除,除后得到的余数记录下来,在循环之后把未处理掉的余数那几个处理下就好。代码里没,憋尿急忙忙写的 /:^|
for (unsigned int * tempPtrToBuf_UIarry= Buffer_UIarry, * EndPtrToBuf_UIarry= &Buffer_UIarry[100000000]; tempPtrToBuf_UIarry<EndPtrToBuf_UIarry; tempPtrToBuf_UIarry= tempPtrToBuf_UIarry+ 6)
{
__asm


{
mov eax, [tempPtrToBuf_UIarry];
mov ebx, [tempPtrToBuf_UIarry+ 0x4];
mov ecx, [tempPtrToBuf_UIarry+ 0x8];
mov edx, [tempPtrToBuf_UIarry+ 0xc];
mov esi, [tempPtrToBuf_UIarry+ 0x10];
mov edi, [tempPtrToBuf_UIarry+ 0x14];

and eax, 0xffff0000;
and ebx, 0xffff0000;
and ecx, 0xffff0000;
and edx, 0xffff0000;
and esi, 0xffff0000;
and edi, 0xffff0000;

and [tempPtrToBuf_UIarry], eax;
and [tempPtrToBuf_UIarry+ 0x4], ebx;
and [tempPtrToBuf_UIarry+ 0x8], ecx;
and [tempPtrToBuf_UIarry+ 0xc], edx;
and [tempPtrToBuf_UIarry+ 0x10], edi;
and [tempPtrToBuf_UIarry+ 0x14], esi;
}
}

//把互相之间没有依存关系的指令写到连续的一起,可以被CPU同时载入连续的多条指令同时执行掉。记得现在的指令流水线应该是同时执行5个指令,这样的话性能应该已不错了。
[解决办法]
不知道做异或速度怎么样?应该不会很慢的把
[解决办法]
第一种方法,应该是最快的。&运算,比加减法还快。
[解决办法]
unsigned int ui=0x12345678u;
ui&=0xffff0000u;

或者
__asm {
 mov eax,ui
 xor ax,ax
 mov ui,eax
}
[解决办法]
43汇编不错,查表怎么样,不过空间悲剧了
[解决办法]
感谢caozhy的认真详细的回复和解答
[解决办法]

[解决办法]
内容存入剪贴板

[解决办法]
我的写法是
*((ushort*)test)=0;

至于你说的慢10倍,那纯属扯淡

第一
上面的语句最终编译成的汇编指令也许是
mov dword ptr [test地址], 0
这样根本就不会吧16bit的数放到寄存器里
被放到寄存器里的也只是test变量的地址

第二
就算编译器犯二,编译成
mov ax, 0
mov dword ptr [test], ax
其中 mov ax也不会比 mov eax慢,编译器会对齐内存
而且16bit的内存对齐比32bit更容易对齐


探讨
to 18#

你这样是用的格式转换。
而事实上CPU最恨你用比它的寄存器小的大小来操作数据,比方带16bits寄存器的一句指令要比正常的32bits寄存器的指令慢10倍。

但为什么不就这样最简单有效呢:
short temp_shortI= In_Dw&amp; 0xffff0000;
只有一个寄存器指令,改善成这样可以提高一些效率 /:^]:


unsigned int……

[解决办法]
test &= 0xffff0000,这是推荐用法,简单易懂,
至于*((ushort*)test)=0;完全是垃圾写法,代码难看就不说了,使用了unsafe也不说了,最令人愤怒的是性能竟然没有提高,这样写只为了增加阅读难度?
[解决办法]
123都是32次位操作,应该一样快的
[解决办法]
楼主发这个帖子就是为了找出尽可能多的做法,
不管这种方法是好是坏,也是一种解决方案

另外,你两个语句都写不对,还说是垃圾?连个取地址符号都不懂,真不知道你的星星怎么来的
感情现在的csdn每天灌个水就可以混出星星来。

探讨
test &amp;= 0xffff0000,这是推荐用法,简单易懂么,
至于*((ushort*)test)=0;完全是垃圾写法,代码难看就不说了,使用了unsafe也不说了,最令人愤怒的是性能竟然没有提高,这样写只为了增加阅读难度?

[解决办法]
123都是32次位操作,应该一样快的
[解决办法]
学习了 怪不得我的这么慢 原来问题是少了一0
[解决办法]
支持并行运算
[解决办法]
探讨
引用:
支持并行运算


并行运算是基于多任务的 咱现在讨论的是运算符的效率 跟并行没关系

我还知道 8核心的肯定比4核心的并行快呢 您说是不?



[解决办法]
有这么多人,谢谢分享

热点排行