搜索
bottom↓
回复: 47

讨论一下字节倒序的最快算法??

[复制链接]

出0入0汤圆

发表于 2008-8-22 14:05:38 | 显示全部楼层 |阅读模式
诸位.我想实现一个字节的倒序,例如  11001100  ---->  00110011.
使用C语言实现
uint8 B2B(uint8  xx)
{
  uint8 yy=0;
  yy=((xx<<7)&0x80)|((xx<<5)&0x40)|((xx<<3)&0x20)|((xx<<1)&0x10)|((xx>>7)&0x01)|((xx>>5)&0x02)|((xx>>3)&0x04)|((xx>>1)&0x08);
  return yy;
}
似乎很繁琐,那位有更好的办法,实现最快的变换速度!

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2008-8-22 14:10:25 | 显示全部楼层
最新的cortex内核支持一条汇编指令直接完成倒序。1个还是2个时钟周期,最快了。avr的话用几条汇编也应该比c的快点吧!个人陋解。

出0入0汤圆

 楼主| 发表于 2008-8-22 14:21:44 | 显示全部楼层
哦.基于目前的情况,使用C51的思路,有无更快的办法,讨教

出0入0汤圆

发表于 2008-8-22 14:56:48 | 显示全部楼层
查表

出0入0汤圆

发表于 2008-8-22 14:58:15 | 显示全部楼层
楼主贴出来的代码感觉编译出来代码量会比较大,用循环应该好点。至于速度那种快用编译后软件仿真一下就知道了。

uint8_t B2B(uint8_t  xx)
{
        uint8_t yy = 0;
        uint8_t i = 1;

        do
        {
                if ((xx & i) > 0)
                {
                        yy++;
                }
                yy = yy << 1;
                i = i << 1;
        }
        while (i != 0);
               
        return yy;
}

出0入0汤圆

发表于 2008-8-22 15:07:59 | 显示全部楼层
看看这个
sbit A_0=ACC^0;//方便位操作
sbit A_1=ACC^1;
sbit A_2=ACC^2;
sbit A_3=ACC^3;
sbit A_4=ACC^4;
sbit A_5=ACC^5;
sbit A_6=ACC^6;
sbit A_7=ACC^7;

sbit B_0=B^0;//方便位操作
sbit B_1=B^1;
sbit B_2=B^2;
sbit B_3=B^3;
sbit B_4=B^4;
sbit B_5=B^5;
sbit B_6=B^6;
sbit B_7=B^7;
unsigned char SetData(unsigned char DataByte)
{
        ACC=DataByte;
        B_0=A_7;
        B_1=A_6;
        B_2=A_5;
        B_3=A_4;
        B_4=A_3;
        B_5=A_2;
        B_6=A_1;
        B_7=A_0;
        return B;
}

基于51的

出0入0汤圆

发表于 2008-8-22 15:11:02 | 显示全部楼层
查表,一条语句解决 return tab[xx];
缺点:表需要占用256个字节的空间

出0入0汤圆

 楼主| 发表于 2008-8-22 15:18:45 | 显示全部楼层
试验证明使用ilcvm的方法速度上要慢于我所用的办法.
查表是最快的le ,好办法,也可行.

出0入0汤圆

 楼主| 发表于 2008-8-22 15:19:28 | 显示全部楼层
位操作暂不考虑

出0入0汤圆

发表于 2008-8-22 15:22:11 | 显示全部楼层
xx=~xx;

xx=xx^0xff;

出0入0汤圆

发表于 2008-8-22 15:37:58 | 显示全部楼层
论速度的话,应该不会有比查表更快的了

出0入0汤圆

发表于 2008-8-22 16:06:36 | 显示全部楼层
假设x为 0b00001011

x = ((x & 0x55) << 1) | ((x & 0xaa) >> 1);

x = ((x & 0x33) << 2) | ((x & 0xcc) >> 2);

x = ((x & 0x0f) << 4) | ((x & 0xf0) >> 4);

x = x >> 4;

这时x为00001101,就这样用位运算速度很快。

出0入0汤圆

发表于 2008-8-22 16:24:42 | 显示全部楼层
查表的话可以分两半来查,兼顾速度和空间。

出0入0汤圆

 楼主| 发表于 2008-8-22 16:57:47 | 显示全部楼层
使用查表已经满足要求,多谢大家.

出0入0汤圆

 楼主| 发表于 2008-8-22 17:14:31 | 显示全部楼层
admvip 的算法不正确

出0入0汤圆

 楼主| 发表于 2008-8-22 17:34:15 | 显示全部楼层
对于这个问题,我集中归纳了一下,放在我的博客上,请大家浏览.

出0入0汤圆

发表于 2008-8-22 17:52:26 | 显示全部楼层
既然追求速度,如果用查表法就类似
uint8 B2B3(uint8  xx)
{
   return  zjdx[xx];
}

这样的函数的,用inline或宏才能更快,调用函数开销太大。

#define B2B3(v) zjdx[v]


实测在12MHz,标准51下,调用一次5楼的位函数用时29us,调用B2B3函数用时19us,使用B2B3宏用时5us 。

出0入4汤圆

发表于 2008-8-22 18:08:58 | 显示全部楼层
《高效程序的奥秘》("Hacker's Delight", [美] Henry S. Warren, Jr. 著)第7章上面有讲这个内容。

出0入0汤圆

发表于 2008-8-22 18:35:41 | 显示全部楼层
7楼写得是一个4位翻转的算法,类推一下就能得到8位的

x = ((x & 0x55) << 1) | ((x & 0xaa) >> 1);
x = ((x & 0x33) << 2) | ((x & 0xcc) >> 2);
x = ((x & 0x0f) << 4) | ((x & 0xf0) >> 4);  

这就是1字节位翻转的算法,7楼x=x>>4是4位反转的算法,舍弃低4位,去掉这一句就是8位的算法,演算一下就知道了。

原始位置:1 2 3 4 5 6 7 8

第一步后:2 1 4 3 6 5 8 7              //交换相邻的位
第二步后:4 3 2 1 8 7 6 5              //交换相邻的2位
第三步后:8 7 6 5 4 3 2 1              //交换相邻的4位,3条语句,26个时钟周期完成,目的实现!!!


网上很多的,位操作 and 技巧 百度上搜一下。

出0入0汤圆

 楼主| 发表于 2008-8-22 18:47:24 | 显示全部楼层
各位高手让我大开眼界啊

出0入0汤圆

 楼主| 发表于 2008-8-22 18:47:50 | 显示全部楼层
各位DX让我大开眼界

出0入0汤圆

发表于 2008-8-22 18:56:30 | 显示全部楼层
我特别喜欢急速快感,楼上的同志们智慧在闪耀

出0入0汤圆

发表于 2008-8-22 19:32:04 | 显示全部楼层
只是最快吗?有其他要求吗?

感觉硬件算法最快,代码量最小............呵呵

将PA口与PB口对调连接..........PA设置为输出,PB设置为输入

uint8 B2B(uint8  xx)
{
    PORTA = xx;
     
    return PINB;
}

出0入0汤圆

发表于 2008-8-22 22:39:13 | 显示全部楼层
哈哈,我就记得曾经在21ic上讨论了这个问题。提出了一个和楼上一样的“馊主意”。

出0入0汤圆

发表于 2008-8-26 11:27:54 | 显示全部楼层
回22楼:

确实快,不过牺牲硬件资源(用了16个口线)。
楼主要的是如何用C语言实现,也就是如何用软件实现。

出0入0汤圆

发表于 2009-7-9 17:53:51 | 显示全部楼层
【18楼】 admvip  不错

出0入0汤圆

发表于 2009-7-9 18:15:17 | 显示全部楼层
18L的方法,看起来不错,但编译代码也不少...
在ICCAVR中编译出26条指令
如果嵌入汇编的话,使用循环移位,应该只用16条指令...

出0入0汤圆

发表于 2009-7-9 19:23:13 | 显示全部楼层
速度和大小兼顾的方法,半字节查表,而且一般的单片机都支持半字节交换。

unsigned char rev_tab[]={0x00,0x08,0x04,0x0c,0x02,0x0a,0x06,0x0e,0x01,0x09,0x05,0x0d,0x03,0x0b,0x07,0x0f};

unsigned char reverse(unsigned char a)
{
    return rev_tab[a&0x0f] << 4 | rev_tab[a>>4];
}

出0入0汤圆

发表于 2009-7-9 19:25:31 | 显示全部楼层
avr中两次查表花的代码也不小了..
还是循环位移代码少...

出0入0汤圆

发表于 2009-7-9 20:04:06 | 显示全部楼层
很早以前讨论过这个问题了  http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=1908616

出0入0汤圆

发表于 2009-7-9 20:54:16 | 显示全部楼层
比较损的方法,只要两个周期,看了别用砖头砸我

端口PA0接到PB7,PA1--PB6,PA2--PB5 把端口A和B以以上方法连上,然后
OUT   PORTA,R16
IN    R16,PINB

只要两个周期就够了哈哈,不过要占16个IO口。

出0入0汤圆

发表于 2009-7-9 21:04:02 | 显示全部楼层
蝶形交换是比较有效率的算法
对其进行稍加改进,可以实现任意位序交换
之前用其实现了洗牌交换
用了三次子蝶形交换

出0入0汤圆

发表于 2009-7-9 23:07:41 | 显示全部楼层
方法1:
源数->R16,结果->R17,花费16T
    asm("ROR        R16");
    asm("ROL        R17");//1
    asm("ROR        R16");
    asm("ROL        R17");//2
    asm("ROR        R16");
    asm("ROL        R17");//3
    asm("ROR        R16");
    asm("ROL        R17");//4
    asm("ROR        R16");
    asm("ROL        R17");//5
    asm("ROR        R16");
    asm("ROL        R17");//6
    asm("ROR        R16");
    asm("ROL        R17");//7
    asm("ROR        R16");
    asm("ROL        R17");//8
===========================
方法2:源数->R16,结果->R16,花费15T
    asm("swap R16 ");
    asm("mov  R17,R16 ");
    asm("lsl  R17 ");
    asm("lsl  R17 ");
    asm("lsr  R16 ");
    asm("lsr  R16 ");
    asm("andi R17,0xcc ");
    asm("andi R16,0x33 ");
    asm("or   R16,R17 ");
    asm("mov  R17,R16 ");
    asm("lsl  R17 ");
    asm("lsr  R16 ");
    asm("andi R17,0xaa ");
    asm("andi R16,0x55 ");
    asm("or   R16,R17 ");

出0入0汤圆

发表于 2010-3-7 17:21:50 | 显示全部楼层
好贴!!

出0入0汤圆

发表于 2010-3-7 21:51:19 | 显示全部楼层
mark!

出0入0汤圆

发表于 2010-3-7 22:20:09 | 显示全部楼层
niu

出0入0汤圆

发表于 2010-3-7 22:38:25 | 显示全部楼层
以前用cpld的剩余资源用硬件实现这个东西,就2个寄存器,速度应该算快的。

出0入0汤圆

发表于 2010-3-9 00:37:29 | 显示全部楼层
asm("swap %a");
a = ((a << 2) & 0xcc) | ((a>> 2) & 0x33);
a = ((a << 1) & 0xaa) | ((a>> 1) & 0x55);
混合编程,结果跟【32楼】 snoopyzz 的方法二是一样的,15T

出0入0汤圆

发表于 2010-3-9 00:49:45 | 显示全部楼层
再来个任意序的,16T
unsigned char x,y;
x=PINB;
asm("bst %x,0"); asm("bld %y,7");
asm("bst %x,1"); asm("bld %y,6");
asm("bst %x,2"); asm("bld %y,5");
asm("bst %x,3"); asm("bld %y,4");
asm("bst %x,4"); asm("bld %y,3");
asm("bst %x,5"); asm("bld %y,2");
asm("bst %x,6"); asm("bld %y,1");
asm("bst %x,7"); asm("bld %y,0");
PORTC=y;

以上是倒序的另一方法,只要改变右边的数字顺序就可以用16T完成任意顺序转换。
AVR的T类似51的进位位C。

出0入0汤圆

发表于 2011-7-20 10:20:35 | 显示全部楼层
LTOR:  MOV   R0,       #8
       MOV   R1,       #0
LOOP:  MOV   A,        R7
       RLC   A
       MOV   R7,       A
       MOV   A,        R1
       RRC   A
       MOV   R1,       A
       DJNZ  R0,       LOOP
       MOV   R7,       A
       RET
END

出0入0汤圆

发表于 2011-7-20 10:36:05 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-8-10 22:12:09 | 显示全部楼层
忘了标记

出0入0汤圆

发表于 2011-8-10 22:58:32 | 显示全部楼层
位操作

出0入0汤圆

发表于 2011-8-10 23:23:11 | 显示全部楼层
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=4039405

出0入0汤圆

发表于 2011-11-29 18:00:39 | 显示全部楼层
mark了,正在用18楼的算法。

出0入0汤圆

发表于 2011-11-29 19:42:08 | 显示全部楼层
mark了

出0入0汤圆

发表于 2013-1-31 22:19:36 | 显示全部楼层
Mark fft REIT

出0入0汤圆

发表于 2013-2-1 10:19:25 | 显示全部楼层
const unsigned char Table[16] =                                 //字节倒序查询表
{0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF,};

LCD_BUS = Table[disp_Comm >>4] | (Table[disp_Comm & 0x0F] <<4);

有一次我把液晶屏画反了,就是这样补救的
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-16 02:23

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表