从键盘任意输入10个整数存入数组,自定义函数float add(int a[],int n))计算数组中正数的平均数,编写main函数测试add函数
时间: 2024-03-21 15:39:30 浏览: 83
好的,以下是一个示例代码:
```python
# 自定义函数,计算数组中正数的平均数
def add(a, n):
sum = 0
count = 0
for i in range(n):
if a[i] > 0:
sum += a[i]
count += 1
if count > 0:
return sum / count
else:
return 0
# 主函数,测试 add 函数
if __name__ == '__main__':
# 从键盘输入 10 个整数
a = []
for i in range(10):
num = int(input("请输入第{}个整数:".format(i+1)))
a.append(num)
# 调用 add 函数计算正数平均数
avg = add(a, 10)
# 输出结果
print("数组中正数的平均数为:{}".format(avg))
```
您可以将这段代码复制到您的 Python 环境中运行,然后按照提示输入 10 个整数即可。程序会输出这 10 个数中正数的平均数。
相关问题
如何将以下代码改为sin的泰勒展开式 ; ;================================================================= ; 函数: _cosine_basic ; 功能: 泰勒展开计算cos(x), 输入Q14, 输出Q15 ; 优化: 保留原始逻辑,增强注释和错误处理 ; 范围:0x0000(0.0)到 0x7FFF(≈1.999939)对应 浮点范围 [0, π/2] ; 值计算:x_float = (int16_t)x_Q14 / 16384.0 (例如 0x6487 对应 π/2 ≈ 1.5708)。 ; 若输入超出 [0, π/2],跳转到 error_basic 返回 1.0(Q15 的 32767)。 ; 泰勒展开式: 1.0 - (x²/2!) + (x⁴/4!) - (x⁶/6!) ;================================================================= .mmregs .data _icosCoef_basic: .word 32767, -16383, 1365, -45 ; 泰勒系数 [1, -1/2!, 1/4!, -1/6!] .sect ".text" .def start start: MOV #0x4305, T0 ; 加载x 60度 #0x4305到 T0 ;--- 输入验证 --- MOV #0x6487, T1 ; 加载 π/2 的 Q14 值到 T1 CMP T0 > T1, TC1 ; 检查 T0 > π/2 BCC error_basic, TC1 MOV #0, T1 ; 加载 0 到 T1 CMP T0 < T1, TC1 ; 检查 T0 < 0 BCC error_basic, TC1 ;--- 主计算逻辑 --- AMOV #(_icosCoef_basic+3), XAR3 ; 系数从高阶项开始 MOV T0, HI(AC0) SQR AC0, AC0 ; AC0 = x² (Q28) SFTS AC0, #-15 ; x²转为Q13 MOV AC0, T0 ; T0 = x² ; 计算高阶项: (-1/6! x² + 1/4!) x² MPYM *AR3-, T0, AC0 ; AC0 = -45 * x² (Q15*Q13=Q28) SFTS AC0, #-13 ; Q28→Q15 ADD *AR3-, AC0 ; AC0 += 1365 MOV AC0, *AR1 MPYM *AR1, T0, AC0 ; AC0 *= x² SFTS AC0, #-13 ; 计算低阶项: (-1/2! + AC0) x² + 1.0 ADD *AR3-, AC0 ; AC0 += -16383 MOV AC0, *AR1 MPYM *AR1, T0, AC0 SFTS AC0, #-13 || MOV *AR3, T0 ; 并行加载1.0 ADD AC0, T0 ; T0 = 结果 Q15 RET error_basic: MOV #32767, T0 ; 返回cos(0)=1.0 RET
<think>好的,我现在需要帮用户将计算余弦泰勒展开的代码改为计算正弦的泰勒展开。首先,我得回忆一下正弦和余弦的泰勒展开式有什么区别。余弦的展开式是1 - x²/2! + x⁴/4! - x⁶/6!,而正弦的展开式是x - x³/3! + x⁵/5! - x⁷/7!,所以结构上不同,正弦的奇数次项,系数也不同。
接下来,我需要分析用户提供的代码结构。原代码是针对余弦的,系数数组是四个数:32767, -16383, 1365, -45,对应的是1, -1/2!, 1/4!, -1/6!。而正弦的展开式需要不同的系数,比如x项是1/1!,然后是-1/3!,接着是1/5!,可能到x⁵或者更高次项。但原代码中用了三次乘法,对应的是三次项,所以可能需要调整展开式的次数。
原代码中的泰勒展开式是三次多项式,但看起来是计算到x⁶,不过代码里用三次乘法。例如,原代码先计算x²,然后进行三次乘法,系数数组有四个元素。所以可能需要将正弦的展开式调整到同样的次数,比如x, x³, x⁵,但次数可能不够,或者需要调整阶数。
另外,代码结构方面,原来的余弦展开是从高阶项开始累加,系数数组的顺序是-1/6!,1/4!,-1/2!,1。而正弦的话,可能需要系数顺序类似,比如从高阶到低阶,比如-1/5!,1/3!,-1/1!,然后乘以x。但需要具体计算每个系数对应的Q格式值。
首先,确定正弦泰勒展开的项数。原代码用了三个非零系数(除了最高项),所以可能需要截断到三次或五次项。例如,假设用户希望用x - x³/6 + x⁵/120,即前三项。这样,系数数组可能需要三个系数,对应1/1!, -1/3!, 1/5!。但原代码中的数组有四个元素,可能需要调整。
原代码中的系数存储顺序是:高阶到低阶。例如,原来的系数数组是[1, -1/2!, 1/4!, -1/6!],但代码中从高阶开始,即先处理-1/6!,然后是1/4!,接着是-1/2!,最后是1。因此,对于正弦的展开式,假设展开到x⁵,即三次项,那么系数数组应该是[1/1!, -1/3!, 1/5!],可能需要四个元素吗?或者可能结构不同?
或者,原代码的泰勒展开式实际上是将多项式表示为1 + x²*( -1/2! + x²*(1/4! + x²*(-1/6!)) )。所以,对于余弦,是1 + x²*(a + x²*(b + x²*c))。而正弦的话,应该是x*(1 + x²*(a + x²*(b + x²*c))),其中a=-1/3!, b=1/5!, c=-1/7!。但原代码可能只计算到x⁵,所以可能需要调整阶数。
现在需要将原来的计算结构改为正弦的结构。原代码中的计算步骤是:
1. 计算x²,然后进行三次乘法,每次乘以x²,并加上系数。
对于正弦,展开式是x - x³/6 + x⁵/120 - x⁷/5040,可能只取前三项的话,就是x - x³/6 + x⁵/120。那么可以表示为x*(1 - x²/6 + x⁴/120)。这样,结构类似于1 + x²*(a + x²*b),但需要乘以x。
因此,代码需要先计算x,然后在多项式部分处理x²的项。原来的代码中,多项式部分处理的是x²的乘积,所以可能需要调整系数数组,并最后乘以x。
具体步骤可能包括:
1. 计算x的原始值,保存起来。
2. 计算x²,然后用类似的结构计算多项式部分,比如1 - x²/6 + x⁴/120。
3. 最后将这个多项式乘以x,得到sin(x) = x*(1 - x²/6 + x⁴/120)。
原代码中的系数数组是四个系数,但正弦可能需要三个系数,比如[1, -1/6, 1/120]。不过要转换成Q格式的值。
原来的系数数组存储的是Q15格式的值。例如,原来的1.0是32767(即0x7FFF),对应的Q15的1.0。所以需要将每个系数转换为Q15的整数值。
例如,正弦展开的系数:
1/1! = 1 → Q15的32767?
不过原代码中的第一个系数是32767对应1.0,可能这里需要调整。比如,原余弦的系数数组中的第一个系数是1,对应32767。而正弦的展开式中的最高阶项是-1/3!,即-1/6 ≈ -0.1666667,对应的Q15值可能是-0.1666667 * 32768 ≈ -5461。同样,1/5! = 1/120 ≈ 0.0083333,对应的Q15是≈273。可能更低的项比如x⁷的系数会更小,但可能被忽略。
原代码中的展开式用了三个系数项,所以正弦可能需要类似的项数。假设用户希望使用泰勒展开到x⁵,即三个项:x - x³/6 + x⁵/120。那么对应的多项式结构是x*(1 - x²*(1/6 - x²*(1/120)))。所以,系数数组应该是 [ -1/6, 1/120 ],但可能需要调整顺序?
或者,原代码的结构是每次将当前结果乘以x²,然后加上下一个系数。例如,原代码中,系数数组的顺序是-45(对应-1/6! ≈ -0.0013889),然后是1365(对应1/4! ≈ 0.0416667),然后是-16383(对应-1/2! =-0.5),最后是32767(1.0)。
所以,原代码中的多项式计算方式是:((c3 * x² + c2) * x² + c1) * x² + c0,其中c3是-1/6!,c2是1/4!,c1是-1/2!,c0是1.0。然后总和是c0 + c1*x² + c2*x^4 + c3*x^6。
对于正弦的情况,可能的结构是x * (d0 + d1*x² + d2*x^4 + d3*x^6),其中d0=1,d1=-1/3!,d2=1/5!,d3=-1/7!。假设用户想展开到x^5,则可能忽略d3项,所以系数数组为 [1, -1/6, 1/120]。
所以,计算步骤可能是:
1. 计算x²。
2. 计算多项式部分:1 + x²*( -1/6 + x²*(1/120) )。
3. 乘以x,得到sin(x)。
那么,系数数组应该是三个系数:1, -1/6, 1/120。转换为Q15的话,需要计算每个系数的整数值。
原来的余弦系数数组是四个元素,但这里可能需要三个系数,或者调整结构。例如,原代码中的系数数组是四个元素,因为余弦的展开式有四次项,但这里可能需要调整。
现在需要确定系数数组的各个值对应的Q15格式:
对于系数:
d0 = 1 → Q15的32767。
d1 = -1/6 ≈ -0.1666667 → Q15的值为-0.1666667 * 32768 ≈ -5461.333,取整为-5461,即0xEA4B。
d2 = 1/120 ≈ 0.00833333 → 0.00833333 * 32768 ≈ 273.0666,取整为273,即0x0111。
但原代码中的系数数组是四个元素,可能这里需要考虑是否要扩展到更多项或者调整结构。例如,如果用户希望展开到x⁵,那么系数数组应该是三个元素:d0, d1, d2。但原代码中的处理方式是使用四次项?或者原代码的结构可能需要调整。
原代码中,系数数组是四个元素,对应四个系数,其中高阶项在数组的末尾。例如,原数组是_icosCoef_basic: .word 32767, -16383, 1365, -45,对应的顺序是c0, c1, c2, c3,而代码中XAR3初始化为_icosCoef_basic+3,即从最高阶的c3开始处理。例如,原代码中的注释说系数是[1, -1/2!, 1/4!, -1/6!],而存储顺序是32767(c0=1),-16383(c1=-1/2!),1365(c2=1/4!),-45(c3=-1/6!)。但是在计算时,代码从c3开始,即AR3指向-45,然后递减到1365,-16383,最后是32767。
这可能意味着原代码的多项式结构是c3*x^6 + c2*x^4 + c1*x^2 + c0。或者更可能的是,原代码的多项式计算方式为:
计算过程是:首先取c3,乘以x²,然后加上c2,再乘以x²,加上c1,再乘以x²,最后加上c0。也就是:
((c3 * x² + c2) * x² + c1) * x² + c0
这等价于 c3*x^6 + c2*x^4 + c1*x^2 + c0。而原余弦的多项式是1 -x²/2! +x^4/4! -x^6/6!,所以对应的c3是-1/6!,c2是1/4!,c1是-1/2!,c0是1.0。
所以,对于正弦的展开式,如果我们采用类似的结构,但最后乘以x的话,那么需要将多项式部分结构改为:
sin(x) = x * (d0 + d1*x² + d2*x^4 + d3*x^6 )
这里的d0=1,d1=-1/3!,d2=1/5!,d3=-1/7!。假设用户希望展开到x⁷,则系数数组需要四个元素。否则,如果只展开到x⁵,则d3=0,可以忽略。
因此,系数数组可能需要四个元素:d0=1, d1=-1/6, d2=1/120, d3=-1/5040。对应的Q15值:
d0=1 → 32767 (0x7FFF)
d1=-1/6 ≈ -0.1666667 → -5461 (0xEA4B)
d2=1/120 ≈ 0.00833333 → 273 (0x0111)
d3=-1/5040 ≈ -0.0001984127 → -6.5027,取整为-7 (0xFFF9)
这可能太小,在Q15下可能无法准确表示,所以可能用户希望只展开到x⁵,忽略x⁷项。这样的话,系数数组是三个元素:d0, d1, d2。但原代码中的结构需要四个系数,因此可能需要调整系数数组的长度或者处理方式。
现在回到原问题,用户可能希望将代码改为计算sin的泰勒展开式,可能只需要前三项,即x -x³/6 +x^5/120。因此,对应的多项式结构是x*(1 - x²*(1/6 -x²*(1/120)))。这需要系数数组中的系数是-1/6, 1/120,然后乘以x²两次,加上初始的1.0。
但原代码中的结构是四次系数,所以可能需要调整。例如,将系数数组设为三个元素:1.0(d0),-1/6(d1),1/120(d2)。然后在计算时,初始值是d2,乘以x²,加上d1,再乘以x²,加上d0,最后乘以x。
或者,考虑到原代码的结构,可能需要将系数数组设置为从高阶到低阶的顺序。例如,假设展开到x^5,则最高阶项是x^5,对应的系数是1/120,即1/5!。在展开式中,多项式部分是1 - x²/6 + x^4/120,即可以看作1 + x²*(-1/6 + x²*(1/120))。因此,系数数组应为 [1/120, -1/6, 1],但原代码中的结构是从最高阶开始,所以系数数组应该按顺序为1/120, -1/6, 1。但原代码中的系数数组有四个元素,可能需要补零或调整项数。
但原代码中的余弦展开式用了三个乘法步骤,对应四个系数。例如,原代码中,系数数组有四个元素,但在计算时,初始XAR3指向第四个元素(-45),然后三次循环:三次MPYM操作,每次取一个系数。因此,对于正弦的情况,可能需要四个系数,但其中某些可能为零,或者调整项数。
这可能比较复杂。例如,假设用户希望将sin展开到x^5,即三次项,那么对应的多项式是x*(1 -x²/6 +x^4/120)。这里,最高阶是x^4,对应的系数是1/120,所以在计算时需要两个系数:1/120和-1/6。然后计算方式为:1/120 *x² + (-1/6),再乘以x²,加1,然后乘以x。
因此,系数数组应该有三个元素:1/120, -1/6, 1。对应的Q15值分别是273, -5461, 32767。存储顺序应该从高阶开始,即系数数组的顺序是1/120, -1/6, 1。但原代码中的系数数组有四个元素,所以可能需要调整,或者用户允许改变数组长度。
在原代码中,系数数组被定义为:
_icosCoef_basic:
.word 32767, -16383, 1365, -45
四个元素,对应四个系数。如果要改为sin的展开式,可能需要同样四个系数,或者改变数组长度。但可能用户希望保持结构不变,所以可能需要四个系数,其中最高阶可能为0或者忽略。
例如,假设sin展开到x^7,则系数数组需要四个元素:1/5040(或者-1/5040?),1/120, -1/6, 1。但原代码中的最高阶项是-1/6!,即-1/720,约-0.0013889,对应的Q15是-45。而sin的x^7项的系数是-1/7! = -1/5040 ≈-0.0001984,对应的Q15值约为-6.5,可能被四舍五入为-7,存储为0xFFF9。但这可能太小,无法精确表示,所以可能用户希望忽略该高阶项,只计算到x^5。
因此,系数数组可能需要三个元素,但原代码中用了四个。这可能意味着用户需要调整代码中的循环次数或者系数数组长度。或者可能原来的代码中有误,需要重新设计。
现在回到代码分析:
原代码中的多项式计算部分:
1. 初始化XAR3指向_icosCoef_basic+3,即最后一个元素(-45)。
2. 计算x²,保存到T0。
3. MPYM *AR3-, T0, AC0 → AC0 = -45 * x²,然后移位,加上下一个系数(1365)。
4. 然后乘以x²,加上下一个系数(-16383),再乘以x²,加上最后的系数(32767)。
这对应的是多项式:(((-45 * x² + 1365) *x² -16383)*x² +32767)。这些系数转换为浮点数是:
-45 /32768 ≈-0.001373 → 对应-1/6! = -1/720 ≈-0.00138889 → 所以Q15的-45大约是-0.001373,误差可能由于四舍五入。
1365 /32768 ≈0.041656 → 1/24=0.0416667,所以接近。
-16383/32768≈-0.49997 →接近-0.5。
所以,原来的系数数组的Q15值对应的是正确的泰勒系数。
现在对于sin的情况,假设系数数组需要三个元素:
系数为1, -1/6, 1/120。对应的Q15值:
1 →32767(0x7FFF)
-1/6 ≈-0.1666667 →-0.1666667 *32768 ≈-5461.333 →-5461(0xEA4B)
1/120≈0.00833333 →0.00833333*32768≈273.0666 →273(0x0111)
但是原代码中的系数数组有四个元素,所以可能需要补一个零或者调整结构。例如,假设sin的展开式只用到x^5,那么最高阶项是x^5,对应的系数是1/120。所以多项式结构为:1 +x²*(-1/6 +x²*(1/120))。所以系数数组应为:1/120, -1/6, 1。存储顺序为从高阶到低阶,即系数数组顺序是1/120, -1/6, 1,共三个元素。但原代码中的处理方式需要四个元素,可能需要调整。
或者,可能用户希望将展开式截断到与余弦相同的项数,即三次项,但次数不同。这可能需要重新设计系数数组。
另一个问题是,原代码中的计算结果是cos(x),而sin(x)的结构需要最后乘以x。因此,在代码的最后部分,需要将多项式的结果乘以x,而原代码中没有这一步。
因此,修改步骤可能包括:
1. 修改系数数组为sin的泰勒系数,例如1, -1/6, 1/120,存储顺序可能从高阶到低阶。
2. 计算多项式部分,类似原代码的结构,但最后需要将结果乘以x。
3. 调整Q格式的精度,因为原来的输入是Q14,输出是Q15,而乘以x(Q14)后,结果的Q格式可能需要调整。
具体步骤:
1. 输入x是Q14格式,范围为[0, π/2]。需要计算sin(x)的泰勒展开。
2. 计算x²:输入x是Q14,平方后得到Q28,然后右移15位转为Q13,存到T0。
3. 多项式部分计算:
sin(x) = x*(1 - x²/6 + x⁴/120) = x*(1 + x²*(-1/6 + x²*(1/120)))
因此,系数数组的顺序应为1/120(高阶项),-1/6,1(低阶项)。系数数组应该有三个元素,但原代码中的数组有四个元素,所以可能需要调整,例如补一个零作为最高阶项,或者修改循环次数。
假设系数数组定义为三个元素,那么在代码中需要调整AR3的初始位置,例如指向第三个元素(假设数组是[1, -1/6, 1/120],存储顺序是1/120, -1/6, 1)。或者可能存储顺序为从高阶到低阶,即系数数组是1/120, -1/6, 1,共三个元素。
原代码中的系数数组是四个元素,所以可能需要调整数组大小。假设用户允许修改数组的大小,那么新的系数数组将是三个元素。但原代码中的计算结构处理四次乘法,可能需要调整循环次数。
或者,可能将系数数组定义为四个元素,其中最高阶项为0,但这样会浪费空间。或者,可能用户希望保持系数数组的大小,所以可能需要调整泰勒展开的项数。
例如,假设展开到x^7,即四项:x -x^3/6 +x^5/120 -x^7/5040,则系数数组需要四个元素:1, -1/6, 1/120, -1/5040。对应的Q15值:
1 →32767
-1/6 →-5461
1/120 →273
-1/5040≈-0.0001984 →-0.0001984*32768≈-6.5 →-7(0xFFF9)
系数数组存储顺序为从高阶到低阶:-7(-1/5040),273(1/120),-5461(-1/6),32767(1)。
然后,计算过程为:
((( -7 * x² + 273 ) *x² -5461 ) *x² +32767 ),然后将结果乘以x。
这可能更接近原代码的结构,因为系数数组有四个元素。但计算出来的结果需要乘以x,得到最终的sin(x)值。
现在,如何将这些系数转换为Q15的整数值:
例如:
-1/5040 ≈-0.0001984127 → Q15的值为-0.0001984127 * 32768 ≈-6.5 →取整为-7 →0xFFF9。
1/120≈0.00833333 →273.0666 →273 →0x0111.
-1/6≈-5461.333 →-5461 →0xEA4B.
1 →32767 →0x7FFF.
因此,系数数组应该是:.word 32767, -5461, 273, -7。但存储顺序需要从高阶到低阶吗?因为在原代码中,系数数组的顺序是[1, -1/2!, 1/4!, -1/6!],即从低阶到高阶存储,但代码中从数组末尾开始取。例如,原数组是32767, -16383, 1365, -45,而代码中XAR3初始化为_icosCoef_basic+3,即最后一个元素(-45),然后依次递减。所以,原代码中的系数数组顺序是c0, c1, c2, c3,而计算时从c3开始。因此,在sin的情况中,如果系数数组存储顺序是c0, c1, c2, c3,其中c0是1,c1是-1/6,c2是1/120,c3是-1/5040,那么代码中需要从c3开始处理。
所以,系数数组应该是:
.word 32767, -5461, 273, -7
对应泰勒展开式中的系数1, -1/6, 1/120, -1/5040。存储顺序是c0, c1, c2, c3,代码中XAR3初始化为_icosCoef_basic+3,即指向c3(-7),然后处理c2(273),c1(-5461),最后是c0(32767)。
计算多项式时,结构为:
(( (-7 * x² +273) *x² -5461 ) *x² +32767 )
然后将结果乘以x,得到sin(x) ≈x * ( ... )
这样,多项式部分计算到x^6,但实际泰勒展开式是x -x^3/6 +x^5/120 -x^7/5040。因此,这里可能有一个错误,因为x^7的项需要x^6乘以x,而代码中的多项式部分计算到x^6。但原代码的结构可能允许这样的处理,因为最后会乘以x。
例如,原代码中的多项式部分计算的是cos(x) =1 -x^2/2 +x^4/24 -x^6/720,即到x^6项。而sin(x)的展开式到x^7项的话,可能需要更高的阶数,但用户可能希望截断到x^5或x^7,根据需求。
不管怎样,现在需要将系数数组改为上述四个元素,然后修改代码中的多项式计算部分,最后乘以x。
原代码中的多项式计算部分:
AMOV #(_icosCoef_basic+3), XAR3 ; 指向最后一个系数(c3)
MOV T0, HI(AC0)
SQR AC0, AC0 ; AC0 = x² (Q28)
SFTS AC0, #-15 ; x²转为Q13
MOV AC0, T0 ; T0 = x²
; 计算高阶项: (-1/6! x² + 1/4!) x²
MPYM *AR3-, T0, AC0 ; AC0 = c3 * x²
SFTS AC0, #-13 ; Q28→Q15
ADD *AR3-, AC0 ; AC0 += c2
MOV AC0, *AR1
MPYM *AR1, T0, AC0 ; AC0 *= x²
SFTS AC0, #-13
; 计算低阶项: (-1/2! + AC0) x² + 1.0
ADD *AR3-, AC0 ; AC0 += c1
MOV AC0, *AR1
MPYM *AR1, T0, AC0
SFTS AC0, #-13
|| MOV *AR3, T0 ; 并行加载c0
ADD AC0, T0 ; T0 = 多项式结果 Q15
; 最后,余弦的结果是T0,而正弦需要将T0乘以x,得到sin(x)=x*T0
所以,在正弦的情况中,计算完多项式后的T0是多项式部分的结果,即1 -x²/6 +x^4/120 -x^6/5040,需要再乘以x。
原代码中的输入x是Q14,多项式结果T0是Q15。相乘后,x(Q14)乘以T0(Q15)得到Q14+15=Q29,需要调整到Q15,即右移14位。
因此,在代码的最后部分,需要:
MPY T0, input_x, AC0 ; AC0 = x * T0,其中input_x是原始的x值(Q14),T0是Q15
SFTS AC0, #-14 ; Q29 → Q15
MOV AC0, T0 ; 结果存入T0
但原代码中的输入x在计算x²之后,原始的x值可能已经丢失,所以需要保存原始的x值。
在原代码中,输入x被加载到T0,然后计算x²,覆盖了T0。因此,在计算x²之前,需要保存原始的x值到另一个寄存器或内存中。
例如,在代码的开始部分:
MOV T0, T2 ; 保存原始的x到T2
然后在最后:
MPY T2, T0, AC0 ; T0是多项式结果(Q15),T2是原始x(Q14)
SFTS AC0, #-14
MOV AC0, T0
因此,需要调整代码以保存原始x的值。
综上所述,修改步骤总结如下:
1. 修改系数数组为sin的泰勒系数,存储顺序为从c0到c3:1, -1/6, 1/120, -1/5040,对应的Q15值为32767, -5461, 273, -7。
2. 在输入验证之后,保存原始x的值到另一个寄存器(如T2)。
3. 计算x²,并按照原代码的结构计算多项式部分,得到T0(Q15)。
4. 最后,将T0(多项式结果,Q15)乘以原始x(Q14),调整结果到Q15格式,存入T0。
现在,具体代码修改:
1. 修改系数数组:
_icosCoef_basic → 更名为_isinCoef_basic或其他名字,但原函数名可能改为_sine_basic。或者用户可能希望保持函数名,但这里可能需要修改。
假设系数数组更名为_isinCoef_basic:
.data
_isinCoef_basic:
.word 32767, -5461, 273, -7 ; 系数 [1, -1/6, 1/120, -1/5040]
注意存储顺序是c0, c1, c2, c3,代码中从c3开始处理。
2. 在计算多项式之前,保存原始x的值:
MOV T0, T2 ; T2保存原始x(Q14)
3. 计算多项式部分:
AMOV #(_isinCoef_basic+3), XAR3 ; 指向c3(-7)
MOV T0, HI(AC0)
SQR AC0, AC0 ; x² (Q28)
SFTS AC0, #-15 ; Q28→Q13
MOV AC0, T0 ; T0 = x² (Q13)
; 计算多项式:
MPYM *AR3-, T0, AC0 ; AC0 = -7 * x² (Q15*Q13=Q28)
SFTS AC0, #-13 ; Q28→Q15
ADD *AR3-, AC0 ; AC0 += 273
MOV AC0, *AR1
MPYM *AR1, T0, AC0 ; AC0 = (AC0) * x² (Q15*Q13=Q28)
SFTS AC0, #-13 ; Q15
ADD *AR3-, AC0 ; AC0 += -5461
MOV AC0, *AR1
MPYM *AR1, T0, AC0 ; AC0 = (AC0) * x²
SFTS AC0, #-13
|| MOV *AR3, T0 ; 并行加载32767
ADD AC0, T0 ; T0 = 多项式结果Q15
4. 最后乘以原始x(T2):
MPY T0, T2, AC0 ; AC0 = T0 (Q15) * T2 (Q14) → Q29
SFTS AC0, #-14 ; Q29 → Q15
MOV AC0, T0 ; 结果存入T0
此外,需要修改函数名称和相关注释,例如将_cosine_basic改为_sine_basic,注释中的泰勒展开式改为sin的。
错误处理部分可能不需要修改,因为输入范围仍然是[0, π/2],sin在此范围内是非负的,所以返回错误时可能仍然返回1.0,或者需要调整?原代码中的错误处理返回32767(即1.0 Q15),这可能不适合sin的情况,但用户可能希望保持错误处理相同。
综上,最终的代码修改包括:
- 系数数组改为sin的泰勒系数。
- 保存原始x。
- 计算多项式后乘以原始x。
- 调整Q格式。
可能还需要处理乘法后的溢出问题,因为sin(x)在[0, π/2]的范围是[0,1],所以Q15的0到32767可以表示。
例如,假设x是Q14,最大值为π/2≈1.5708,对应Q14的0x6487。计算sin(x)=1.0,此时多项式部分的结果是1.0,乘以x的Q14值0x6487(≈1.5708),结果Q15为1.5708*32768/16384=1.5708*2=3.1416,这超过了Q15的最大值32767(代表2.0)。这显然有问题,因为sin(π/2)=1.0,所以最终结果应该是32767,但按照上述乘法,会得到1.5708*1.0=1.5708,Q15中的1.5708是0x6487 >>1(因为Q15是符号数,范围-1到≈0.9999695),或者可能存在其他Q格式转换错误。
这说明在Q格式的处理上可能存在错误。需要仔细检查Q格式的转换。
原代码中的输入x是Q14,表示的范围是0到0x7FFF(≈1.999939),但注释说明输入的范围是[0, π/2],即x的浮点值在0到约1.5708。所以输入x的Q14值对应浮点为x_Q14 / 16384.0。
原代码中,cos的输出是Q15,即32767对应1.0。
对于sin的情况,输出也应该是Q15,即32767对应1.0。所以当计算sin(x)时,结果的范围是0到1.0,因此Q15的0到32767是正确的。
问题出在如何将多项式结果乘以x的Q14值,并得到Q15的结果。
原代码中的多项式计算结果T0是Q15,表示的是一个浮点数,例如1.0对应32767。原始x是Q14,表示例如1.5708对应0x6487(Q14的值是0x6487=25735,25735/16384≈1.5708)。
当将这两个值相乘时:
T0(Q15) * x(Q14) = Q15 * Q14 → Q(15+14) = Q29。结果的正确Q格式需要转换为Q15。
例如,假设T0是1.0(Q15的32767),x是π/2(Q14的0x6487=25735),则乘积是1.0 * π/2 ≈1.5708。在Q15中,1.5708对应的值是≈1.5708 * 32768 ≈51472,但这超过了Q15的最大值32767(因为Q15是有符号整数,但实际上这里都是正数,可能需要使用无符号处理?或者原代码中使用的是无符号数?需要查看原代码中的处理方式。)
这可能意味着原来的Q格式设计有问题,或者需要调整乘法后的位移操作。
例如,输入x是Q14,表示无符号数?原代码中的输入验证检查x是否在0到0x7FFF(Q14的正数范围),所以可能是无符号的。
因此,Q14的x的范围是0到1.999939,但实际输入范围是0到π/2≈1.5708。
当计算sin(x) =x*(多项式部分),其中多项式部分的值小于等于1,所以乘积的最大值为1.5708*1.0≈1.5708,而Q15的最大值是≈1.999939,所以1.5708可以表示为Q15的值:1.5708 * 32768 ≈51472,这超过了16位有符号整数的最大值32767,因此需要使用32位累加器或者不同的Q格式处理。
这可能意味着在代码中需要调整乘积的位移方式,或者在乘法时使用更高的精度。
原代码中,MPY指令可能使用32位累加器,例如:
MPY T0, T2, AC0 → AC0 = T0 * T2,其中T0是Q15,T2是Q14,结果为Q29。为了转换为Q15,需要右移14位(因为15+14-15=14位移)。
所以,SFTS AC0, #-14 → Q29 → Q15.
例如,假设T0是32767(Q15的1.0),T2是0x6487(Q14的1.5708),乘积是32767 * 25735 = 842, 1, 842, 1(大数),存储在AC0中。右移14位后,结果为 (32767 * 25735) >>14 ≈ (32767 * 25735) / 16384 ≈ 51471.9 → 51472。但Q15的最大值是32767,这会导致溢出。
这说明这种方法不可行,因为sin(π/2)=1.0,但在计算时得到的是1.0 * π/2,这显然超过了Q15的范围。
这说明之前的想法有误,可能多项式部分的结构需要重新考虑。或者,可能泰勒展开式的结构应该不同,例如,多项式部分应该是sin(x)/x,然后乘以x,但这在数值上可能更稳定。
但原代码中的cos的展开式是直接计算cos(x) =1 -x²/2 +x^4/24 -x^6/720,所以可能在Q格式处理上没有问题,因为cos(x)在[0, π/2]的范围是0到1,所以输出Q15是正确的。但对于sin(x),输出范围是0到1,所以乘以x(最大1.5708)会导致结果超过1,这显然不可能,因为sin(π/2)=1.0。
这说明我的理解有误,可能问题出在如何构造多项式部分。正确的多项式展开式是sin(x) =x -x^3/6 +x^5/120 -x^7/5040,所以应该表示为x*(1 -x²/6 +x^4/120 -x^6/5040)。这样,多项式部分的值是sin(x)/x,当x接近0时接近1,而当x=π/2时,约为1 - (π/2)^2/6 + (π/2)^4/120 - ... ≈0.5708。然后乘以x(π/2≈1.5708)得到sin(x)=1.0。
所以,多项式部分的结果是sin(x)/x,其值在[0, π/2]的范围内是大约[1.0, 0.6366](当x=π/2时,sin(x)/x=2/π≈0.6366)。然后乘以x(最大值1.5708)得到sin(x)的值为1.0。
因此,多项式部分的结果是Q15格式的0.6366对应的值约为0.6366*32767≈20860。乘以x(Q14的1.5708≈25735)得到20860*25735≈536, 0, 536, 0 →536,000,000。右移14位后是536,000,000 /16384 ≈32767,这刚好是Q15的1.0。
这说明Q格式的处理是正确的,前提是多项式部分计算的是sin(x)/x的值,然后乘以x,得到正确的sin(x)值。
因此,正确的步骤应该是:
1. 多项式部分计算的是sin(x)/x =1 -x²/6 +x^4/120 -x^6/5040,其值范围是[0.6366, 1.0]。
2. 这个值的Q15格式最大为1.0(32767),最小约为0.6366*32767≈20860。
3. 乘以x(Q14,最大值1.5708)得到sin(x)的值,例如,当x=π/2时,sin(x)/x≈0.6366,乘以x≈1.5708,得到1.0。在Q格式中,0.6366(Q15)*1.5708(Q14)=1.0(Q15)。
这需要多项式部分的结果(sin(x)/x)是Q15格式,乘以x(Q14)后得到Q29,右移14位得到Q15,即sin(x)的值。
因此,正确的代码修改应包括:
- 系数数组对应的是sin(x)/x的展开式,即1 -x²/6 +x^4/120 -x^6/5040,存储为四个系数,计算方式与原代码类似。
- 最后将多项式结果(Q15)乘以x(Q14),结果转为Q15。
这样,当x=π/2时,多项式部分的结果是0.6366(Q15的20860),乘以x的Q14值25735:
20860 * 25735 = 536, 0, 536, 000 →536,000,000(32位结果)。
右移14位:536,000,000 /16384 ≈32767,即Q15的32767,对应1.0。
因此,Q格式的处理是正确的。
综上所述,正确的步骤如下:
1. 修改系数数组为sin(x)/x的泰勒系数,即1, -1/6, 1/120, -1/5040,对应的Q15值:32767, -5461, 273, -7。
2. 保存原始x的值。
3. 计算多项式部分,得到sin(x)/x的Q15值。
4. 乘以原始x(Q14),右移14位,得到sin(x)的Q15值。
因此,最终的代码修改应为:
;=================================================================
; 函数: _sine_basic
; 功能: 泰勒展开计算sin(x), 输入Q14, 输出Q15
; 优化: 保留原始逻辑,增强注释和错误处理
; 范围:0x0000(0.0)到 0x7FFF(≈1.999939)对应 浮点范围 [0, π/2]
; 值计算:x_float = (int16_t)x_Q14 / 16384.0
; 若输入超出 [0, π/2],跳转到 error_basic 返回 0.0(Q15 的 0)或其他?
; 泰勒展开式: x*(1.0 - (x²/3!) + (x⁴/5!) - (x⁶/7!))
;=================================================================
.mmregs
.data
_isinCoef_basic:
.word 32767, -5461, 273, -7 ; 系数 [1, -1/6, 1/120, -1/5040]
.sect ".text"
.def start
start:
MOV #0x4305, T0 ; 加载x 60度 #0x4305到 T0
;--- 输入验证 ---
MOV #0x6487, T1 ; π/2 Q14值
CMP T0 > T1, TC1
BCC error_basic, TC1
MOV #0, T1
CMP T0 < T1, TC1
BCC error_basic, TC1
;--- 保存原始x到T2 ---
MOV T0, T2
;--- 主计算逻辑 ---
AMOV #(_isinCoef_basic+3), XAR3 ; 从最高阶系数开始
MOV T0, HI(AC0)
SQR AC0, AC0 ; x² (Q28)
SFTS AC0, #-15 ; 转为Q13
MOV AC0, T0 ; T0 = x² (Q13)
; 计算多项式部分:1 - x²/6 + x⁴/120 - x⁶/5040
MPYM *AR3-, T0, AC0 ; -7 * x²
SFTS AC0, #-13 ; Q28→Q15
ADD *AR3-, AC0 ; AC0 += 273
MOV AC0, *AR1
MPYM *AR1, T0, AC0 ; (结果) * x²
SFTS AC0, #-13
ADD *AR3-, AC0 ; AC0 += -5461
MOV AC0, *AR1
MPYM *AR1, T0, AC0 ; (结果) * x²
SFTS AC0, #-13
|| MOV *AR3, T0 ; 加载32767
ADD AC0, T0 ; T0 = 多项式结果(sin(x)/x) Q15
; 乘以原始x(T2)得到sin(x)
MPY T0, T2, AC0 ; AC0 = T0 (Q15) * T2 (Q14) → Q29
SFTS AC0, #-14 ; Q29 → Q15
MOV AC0, T0 ; 结果存入T0
RET
error_basic:
MOV #0, T0 ; 返回sin(0)=0.0 或保持原错误处理?
; 或者根据原代码返回1.0,但sin(0)=0,可能更合理返回0
RET
此外,错误处理部分可能需要修改,原代码返回1.0(32767),但对于sin来说,输入越界应返回0或其他值,但用户可能希望保持与原错误处理一致,或者根据具体情况。假设用户希望返回0,则error_basic处MOV #0, T0。
总结,关键修改点:
- 系数数组调整为sin的泰勒系数。
- 保存原始x。
- 计算多项式部分后乘以原始x。
- 调整错误处理返回0。</think>要将代码从计算余弦(cos)的泰勒展开改为计算正弦(sin)的泰勒展开,需修改系数、多项式结构和最终乘法步骤。以下是具体修改说明:
---
### **1. 修改泰勒展开式**
余弦展开式为:
$$ \cos(x) = 1 - \frac{x^2}{2!} + \frac{x^4}{4!} - \frac{x^6}{6!} $$
正弦展开式为:
$$ \sin(x) = x - \frac{x^3}{3!} + \frac{x^5}{5!} - \frac{x^7}{7!} $$
可改写为:
$$ \sin(x) = x \cdot \left(1 - \frac{x^2}{6} + \frac{x^4}{120} - \frac{x^6}{5040}\right) $$
---
### **2. 调整系数数组**
原余弦系数 `_icosCoef_basic` 对应 `[1, -1/2!, 1/4!, -1/6!]`。
正弦需替换为 `[1, -1/6, 1/120, -1/5040]`,并转换为 Q15 格式:
| 系数值 | Q15 整数值(十六进制) |
|-------------|------------------------|
| 1.0 | 32767 (0x7FFF) |
| -1/6 ≈ -0.1666667 | -5461 (0xEA4B) |
| 1/120 ≈ 0.0083333 | 273 (0x0111) |
| -1/5040 ≈ -0.0001984 | -7 (0xFFF9) |
修改后的系数数组:
```assembly
.data
_isinCoef_basic:
.word 32767, -5461, 273, -7 ; 泰勒系数 [1, -1/6, 1/120, -1/5040]
```
---
### **3. 代码修改步骤**
#### **(1) 保存原始输入 `x`**
计算 `x²` 前需保存原始 `x`(Q14 格式):
```assembly
MOV T0, T2 ; 保存原始 x 到 T2
```
#### **(2) 计算多项式部分**
多项式部分为 `1 - x²/6 + x⁴/120 - x⁶/5040`,需从高阶项开始累加:
```assembly
AMOV #(_isinCoef_basic+3), XAR3 ; 指向最高阶系数 (-1/5040)
MOV T0, HI(AC0)
SQR AC0, AC0 ; 计算 x² (Q28)
SFTS AC0, #-15 ; 转为 Q13
MOV AC0, T0 ; T0 = x² (Q13)
; 计算多项式项: ((-7 * x² + 273) * x² -5461) * x² + 32767
MPYM *AR3-, T0, AC0 ; AC0 = -7 * x²
SFTS AC0, #-13 ; Q28 → Q15
ADD *AR3-, AC0 ; AC0 += 273
MOV AC0, *AR1
MPYM *AR1, T0, AC0 ; (AC0) * x²
SFTS AC0, #-13
ADD *AR3-, AC0 ; AC0 += -5461
MOV AC0, *AR1
MPYM *AR1, T0, AC0 ; (AC0) * x²
SFTS AC0, #-13
|| MOV *AR3, T0 ; 加载 32767 (1.0)
ADD AC0, T0 ; T0 = 多项式结果 (sin(x)/x) Q15
```
#### **(3) 乘以原始 `x`**
将多项式结果乘以原始 `x`(Q14)并转换为 Q15:
```assembly
MPY T0, T2, AC0 ; AC0 = 多项式结果 (Q15) * 原始 x (Q14)
SFTS AC0, #-14 ; Q29 → Q15
MOV AC0, T0 ; 最终结果存入 T0
```
#### **(4) 错误处理**
若输入超出 `[0, π/2]`,返回 `0`(更合理):
```assembly
error_basic:
MOV #0, T0 ; 返回 sin(0) = 0.0
RET
```
---
### **4. 完整修改后的代码**
```assembly
;=================================================================
; 函数: _sine_basic
; 功能: 泰勒展开计算 sin(x),输入 Q14,输出 Q15
; 范围:0x0000(0.0)到 0x7FFF(≈1.999939)对应浮点范围 [0, π/2]
; 若输入超出范围,返回 0.0(Q15 的 0)
; 泰勒展开式: x * (1.0 - (x²/3!) + (x⁴/5!) - (x⁶/7!))
;=================================================================
.mmregs
.data
_isinCoef_basic:
.word 32767, -5461, 273, -7 ; 系数 [1, -1/6, 1/120, -1/5040]
.sect ".text"
.def start
start:
MOV #0x4305, T0 ; 加载 x(示例值)
;--- 输入验证 ---
MOV #0x6487, T1 ; π/2 的 Q14 值
CMP T0 > T1, TC1
BCC error_basic, TC1
MOV #0, T1
CMP T0 < T1, TC1
BCC error_basic, TC1
;--- 保存原始 x ---
MOV T0, T2
;--- 主计算逻辑 ---
AMOV #(_isinCoef_basic+3), XAR3
MOV T0, HI(AC0)
SQR AC0, AC0 ; x² (Q28)
SFTS AC0, #-15 ; Q13
MOV AC0, T0 ; T0 = x²
MPYM *AR3-, T0, AC0 ; -7 * x²
SFTS AC0, #-13 ; Q15
ADD *AR3-, AC0 ; +273
MOV AC0, *AR1
MPYM *AR1, T0, AC0 ; *x²
SFTS AC0, #-13
ADD *AR3-, AC0 ; +(-5461)
MOV AC0, *AR1
MPYM *AR1, T0, AC0 ; *x²
SFTS AC0, #-13
|| MOV *AR3, T0 ; 加载 32767
ADD AC0, T0 ; 多项式结果 (sin(x)/x)
MPY T0, T2, AC0 ; 乘以原始 x
SFTS AC0, #-14 ; Q15
MOV AC0, T0
RET
error_basic:
MOV #0, T0 ; 返回 0.0
RET
```
---
### **关键修改总结**
1. **系数数组**:替换为 sin 的泰勒系数,按 Q15 格式存储。
2. **保存原始 `x`**:在计算 `x²` 前保存原始值,用于最后的乘法。
3. **多项式计算**:从高阶项开始累加,结构为 `(((-7*x² +273)*x² -5461)*x² +32767)`。
4. **最终乘法**:将多项式结果(sin(x)/x)乘以原始 `x`,并调整 Q 格式。
5. **错误处理**:输入越界时返回 `0.0`(Q15 格式)。
阅读全文
相关推荐






