找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4475|回复: 23
收起左侧

纳闷,51单片机无法计算乘积为上万的乘法?

  [复制链接]
ID:71233 发表于 2019-8-29 11:34 | 显示全部楼层 |阅读模式
本帖最后由 新新科技 于 2019-8-29 12:01 编辑

这几天在设计一段程序时,需要计算相乘积为上万甚至上十万的乘法运算,大致是这样的:
      unsigned int tt;//使用STC单片机
      tt=(shuiliang*(100-temp)*0.01;//
其中,shuiliang值为800至1500,temp值为0至100。
通过多次的试验,明明shuiliang(指定1500)和temp(指定30)的代入数值不会出错,但tt的计算结果总是出错(用Proteus_7.5仿真或实物均如此),真的很纳闷,后来通过分析,难道51单片机真的无法计算乘积为上万的乘法?最终确定改变运算顺序(先除,让乘积不再太大),具体如下:
      tt=(shuiliang/100)*(100-temp);
这样的运算顺序,计算结果才是正确的。
请教各位大师,51单片机在做乘法计算的,最大只能完成乘积为多少的乘法运算?

回复

使用道具 举报

ID:149144 发表于 2019-8-29 15:57 | 显示全部楼层
unsigned int tt ; 最大值是多少 ?   65535 ??
1500 * 70 = 105000  
回复

使用道具 举报

ID:401564 发表于 2019-8-29 16:12 | 显示全部楼层
理论上来说,8051可以计算无限大运算,所有运算,包括微积分之类的高数
而实际上,8051的能力只能说是可以无限接近无限,总的来说的,10亿以内的运算是绝对可以的。
对于C的计算来说,它取决于KEIL这个软件的编译器,不同类型的数据类型就会有不同的长度,运算结果超过这个长度的,就会不要了
而在C中,不同数据类型进行运算时,会先强制转换成同一个类型再进行运算,而你这个就是这种情况
你想要运算结果正确,所有的数据类型得是:双精度浮点数,好像KEIL中这个类型应该是有16位的,如果长度是16位的,那么:在65536以下的运算就是正确的,超过这个值的就只取16位的结果,如果是32位长度,那就更精确了
回复

使用道具 举报

ID:149389 发表于 2019-8-29 16:29 | 显示全部楼层
本帖最后由 weidoit 于 2019-8-29 16:46 编辑


1500*(100-30)=105000  (存不下了),试试长整型。
回复

使用道具 举报

ID:71233 发表于 2019-8-29 17:27 | 显示全部楼层
1500*100=150000,乘积超过65536,那是一定的,只不过这个结果不是最终的结果,因为后面还要除以100,具体见上面的计算式子。问题出在KEIL,那是极有可能的,因为我用的版本是7.5版的。
回复

使用道具 举报

ID:401564 发表于 2019-8-30 00:44 | 显示全部楼层
这跟后面除以100没有关系的,超过16位的数字,就只取16位的数据,多出来的就不要了
你可以使用long型数据,,32位,足够你用的了
回复

使用道具 举报

ID:511890 发表于 2019-8-30 01:09 | 显示全部楼层
不是单片机的问题,是C语言变量类型字节长度的问题。U int 最大值65535。把tt的类型unsigned int改为long就行
回复

使用道具 举报

ID:65956 发表于 2019-8-30 08:35 | 显示全部楼层
unsigned int tt;把这个改为unsigned long tt;就OK了,这个最大可以达到4294967295,这是最大值
回复

使用道具 举报

ID:208271 发表于 2019-8-30 08:58 | 显示全部楼层
8051单片机是8位单片机,数据储存器是16位的,最大的数据是65536,超过这个数据单片机储存就有问题,但对于程序来说,就是定义问题,定义int就65536,超过了就会溢出,采用LONG或者FLOAT型,这是编译器的问题。还是要了解一下编译器的C语言用法。
回复

使用道具 举报

ID:208271 发表于 2019-8-30 09:02 | 显示全部楼层
unsigned int tt;//使用STC单片机tt=(shuiliang*(100-temp)*0.01;/
这个tt是int类型,不能*0.01,可以/100,数据类型不对一样出错的,编译器不会自动转换识别数据类型的,把tt改为float可以用*0.01,不会出错。
楼主还是要了解清楚C的数据类型啊!
回复

使用道具 举报

ID:605370 发表于 2019-8-30 09:34 | 显示全部楼层
建议你更换数据类型,int长度不够,试试long
回复

使用道具 举报

ID:71233 发表于 2019-8-30 18:12 | 显示全部楼层
改为
    unsigned long tt;
    tt=(shuiliang*(100-temp)/100;
照常不行!
回复

使用道具 举报

ID:71233 发表于 2019-8-30 18:22 | 显示全部楼层
无论把tt改为什么类型都不行,我总是觉得要么是编译器的限制,要么就是51单片机的只能分配2个字节的寄存器来存储运算过程中的中间数,我检验了,的确在计算乘法的时候,超过两个八位字节的,只截取了后面两个字节的数值,如1500*100=150000=0x249F0,结果只有0x49F0继续参加后面的计算。
回复

使用道具 举报

ID:401564 发表于 2019-8-30 23:08 | 显示全部楼层
我的天呀!为什么会这这种想法呢,根本是你自己的方法不对
所有的变量都统一的改成long型,所有的!
temp不是变量吗?shuiliang是不是呢?
那么多人帮你回答了那么多
你是怎么验证的呢?
还是我前面的回答:10亿以内的运算是可以的,难道你没有见过或者听说过基于8051的计算器吗
回复

使用道具 举报

ID:370639 发表于 2019-8-31 08:24 | 显示全部楼层
数据类型不对吧
回复

使用道具 举报

ID:149642 发表于 2020-6-11 22:31 | 显示全部楼层
汇编都可以算到亿亿以上,只要你的寄存器够多,
ABCDEF*ABCDEF=(AB*100*100+CD*FF+EF)*(AB*100*100+CD*FF+EF)
回复

使用道具 举报

ID:491577 发表于 2020-6-14 18:36 | 显示全部楼层
楼主不明白单片机计算中每一步都不能够有数据溢出,否则出错,不是最后一步不溢出就行。用强制转换就可以了。比如: tt=(shuiliang*(100-temp)/100;改成: tt=((long)shuiliang*(100-temp)/100;
回复

使用道具 举报

ID:877285 发表于 2021-2-1 09:38 | 显示全部楼层
解决问题没,我和你的问题一样
回复

使用道具 举报

ID:712493 发表于 2021-2-1 14:21 | 显示全部楼层
hhh402 发表于 2020-6-14 18:36
楼主不明白单片机计算中每一步都不能够有数据溢出,否则出错,不是最后一步不溢出就行。用强制转换就可以了 ...

看看 这个对头  还是数据类型的问题 不行就一步一步写嘛
回复

使用道具 举报

ID:882150 发表于 2021-2-1 19:26 | 显示全部楼层
数据类型有问题 建议用long
回复

使用道具 举报

ID:877285 发表于 2021-2-2 09:01 | 显示全部楼层
实例1:  gPWM.Duty 输出值为异常值
         Test_A = (long)4580;
          
          Test = (long)Test_A*(long)100;
          
          gPWM.Duty = Test / (gPWM.High_Cnt + gPWM.Low_Cnt);

实例2:  gPWM.Duty 输出值为正常值   
          
          Test = (long)4580*(long)100;
          
          gPWM.Duty = Test / (gPWM.High_Cnt + gPWM.Low_Cnt);

谁能解释为啥?
回复

使用道具 举报

ID:879809 发表于 2021-2-2 18:10 | 显示全部楼层
die123123 发表于 2021-2-2 09:01
实例1:  gPWM.Duty 输出值为异常值
         Test_A = (long)4580;
          

类似 (long)4580的写法改成4580l。
回复

使用道具 举报

ID:158467 发表于 2021-7-6 09:39 | 显示全部楼层
Y_G_G 发表于 2019-8-30 23:08
我的天呀!为什么会这这种想法呢,根本是你自己的方法不对
所有的变量都统一的改成long型,所有的!
temp不是 ...

统一换成长整型也有问题,这个跟编译器的IDE是否能自动识别 类型和准确隐式转换有关,存在常量100就会默认为表达式为16位的运算,解决方法1是如楼主的:前面先除以100,控制数据在16位数据内,这样是可以的。另一种方法是:先定义位unsiged long  tt;   tt=((unsiged long)shuiliang/(unsiged long)100)*((unsiged long)100-(unsiged long)temp))
回复

使用道具 举报

ID:158467 发表于 2021-7-6 09:39 | 显示全部楼层
统一换成长整型也有问题,这个跟编译器的IDE是否能自动识别 类型和准确隐式转换有关,存在常量100就会默认为表达式为16位的运算,解决方法1是如楼主的:前面先除以100,控制数据在16位数据内,这样是可以的。另一种方法是:先定义位unsiged long  tt;   tt=((unsiged long)shuiliang/(unsiged long)100)*((unsiged long)100-(unsiged long)temp))
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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