计算正实数的乘法逆
我想在不使用除法的情况下计算正实数的乘法逆。 在阅读了Newton Raphson方法的各个页面后,我实现了以下用于计算逆的代码:
#define PRECISION 0.1e-5 double inverse(double num) { double ans = num; while (ans * num > 1 + PRECISION || ans * num < 1 - PRECISION) { ans = ans * (2 - num * ans); } return ans; }
现在,问题是,我实际上没有得到逆值。 循环无限循环。
所以,我注意到的第一件事是: ans
的价值变为负数,我补充说
if (ans < 0) ans *= -1;
所以ans
始终是积极的。
第二点需要注意:如果我的初始化为ans = 0.5
那么我得到一些num
= (1, 2, 3, 5)
num
值的正确答案。
所以,我的假设是,由于变量ans
初始化不合适,实现不起作用。
所以,最后我的问题:
1.这个方法实际上可以用来计算所有正实数的倒数吗?
2.如果是,那么在使用Newton Raphson方法时,假设初始值是否需要任何条件?
3,有没有其他更好的方法来计算倒数而不使用除法?
编辑:
谢谢你的回答。 所以,正如答案中所提到的,我将ans
初始值改为PRECISION
,它的确有效! 此外,现在因为初始值对于num
特定最大限制是好的,所以ans
永远不会变为负数,因此不需要我最初添加的否定检查条件。
所以,这是工作代码(至少适用于我给出的输入。)
double inverse(double num) { // Added to make it valid for all inputs. // For a too large number under the precision constraint, the answer is 0. if (num > 999999) return 0; double ans = PRECISION; while (ans * num > 1 + PRECISION || ans * num < 1 - PRECISION) { ans = ans * (2 - num * ans); } return ans; }
您应该从(0,2 / num)中选择初始近似值。 如果从2 / num的另一侧选择它,则该方法可能不会收敛:近似将超过0并且序列将倾向于-∞。
为了达到这个间隔,让我们看看ans*(2-num*ans)
改变符号的位置:当2-num * ans <0时,或当ans> 2 / num时,它变为负数。 所以最初ans
应小于2 / num。
为了能够选择一个良好的初始近似值,您必须先了解浮点数的表达方式。 通常,计算机使用x = s * m * 2 e ,其中s是符号,m(“尾数”)在(0.5,1)中,e(“指数”)是整数。 现在1 / x = s * 1 / m * 2 -e ,因此问题减少到计算范围(0.5,1)中数字的倒数,并且在该范围内,您可以使用例如1作为初始猜测。 显然,该范围内的最佳初始猜测是48 / 17-32 / 17 * m 。
对于所有数字s * m * 2 e应该起作用的一个初始猜测是s * 2 -e 。 在C中,这可以计算为:
double ans = num; // Initial guess: ans = 2**(-floor(log num)) long int *t = (long int*)(&ans); *t = (*t & (0x1l<<63)) | (~*t & (0x3FFl << 52)) - (0x1l << 52); /* sign */ /* negative exponent */
(注意:我没有检查边缘条件。)
为了近似x的倒数,仅使用乘法和减法,可以猜测数y,然后用2y-xy ^ 2重复地替换y。 一旦y的变化变得(并且保持)足够小,y就是x的倒数的近似值。
ans =(2 * ans) – (num * ans * ans);
请添加parantheses并尝试
在建设性数学中,对于实数x具有倒数,x≠0是不够的。必须给出有理数r,使得0
每个非零元素具有乘法逆的环是一个除环; 同样,它所代表的代数是一个除法代数。
你想用modulo吗? 在模运算中,a的模乘乘逆也被定义:它是数x,使得ax≡1(mod n)。 当且仅当a和n是互质的时,这种乘法逆存在。
_EDIT_ _ ____
刚才注意到,最初ans = num; ans = 2 * ans-num * ans * ans; => ans = 2 * ans – 3 * ans = -1 * ans
所以它总是一个负值。相信初始化为num不是一个好主意。 尝试将ans设置为1