Ada中用Big_Real计算大数平方根触发STORAGE_ERROR问题求助
解决Ada Big_Real牛顿迭代求平方根的STORAGE_ERROR问题
你的问题根源在于Big_Real是任意精度类型,每次牛顿迭代的运算(除法、乘法)都会不断累积小数位,导致底层存储的分子/分母大整数持续膨胀,最终触发存储上限,抛出STORAGE_ERROR。要解决这个问题,核心是主动控制Big_Real的精度,避免无限制的精度累积。
解决方案1:迭代中强制限制精度
通过Set_Precision函数,在每次迭代后将结果截断到指定的有效数字位数,从根源上阻止精度无限制增长。同时牛顿迭代是二次收敛的,不需要32次迭代,16次以内就足够收敛到极高精度。
修改后的代码:
pragma Ada_2022; with Ada.Numerics.Big_Numbers.Big_Reals; use Ada.Numerics.Big_Numbers.Big_Reals; with Ada.Text_IO; use Ada.Text_IO; function Big_Sqrt(X: Big_Real) return Big_Real is package Converter is new Float_Conversions(Float); use Converter; -- 指定目标十进制有效精度,这里设20位足够覆盖输入需求 Target_Precision : constant Precision := Decimal_Precision(20); Z: Big_Real := Set_Precision(X, Target_Precision); Big_Half: Big_Real := Set_Precision(To_Big_Real(0.5), Target_Precision); begin -- 牛顿迭代二次收敛,16次足够收敛到目标精度 for I in 1..16 loop Z := Set_Precision(Big_Half * (Z + X/Z), Target_Precision); Put_Line(Z'Image); end loop; return Z; end Big_Sqrt;
关键说明:
Decimal_Precision(N):指定保留N位十进制有效数字,根据你的输入(16位整数),设置20位完全足够覆盖平方根的整数+小数部分。- 每次迭代后调用
Set_Precision:强制截断多余的精度,避免底层大整数持续膨胀。 - 减少迭代次数:牛顿迭代的收敛速度是指数级的,10-16次迭代就能达到远超需求的精度,无需32次。
解决方案2:优化初始值进一步降低负担
如果输入是整数(比如你的测试值1813789079679324),可以先用Big_Integers的平方根函数获取近似整数初始值,再代入牛顿迭代,这样能大幅减少迭代次数,进一步降低精度累积的风险。
代码示例:
pragma Ada_2022; with Ada.Numerics.Big_Numbers.Big_Reals; use Ada.Numerics.Big_Numbers.Big_Reals; with Ada.Numerics.Big_Numbers.Big_Integers; use Ada.Numerics.Big_Numbers.Big_Integers; with Ada.Text_IO; use Ada.Text_IO; function Big_Sqrt(X: Big_Real) return Big_Real is package Converter is new Float_Conversions(Float); use Converter; Target_Precision : constant Precision := Decimal_Precision(20); X_Int : constant Big_Integer := To_Big_Integer(X); -- 用整数平方根作为初始值,大幅加快收敛速度 Z: Big_Real := Set_Precision(To_Big_Real(Sqrt(X_Int)), Target_Precision); Big_Half: Big_Real := Set_Precision(To_Big_Real(0.5), Target_Precision); begin for I in 1..8 loop Z := Set_Precision(Big_Half * (Z + X/Z), Target_Precision); Put_Line(Z'Image); end loop; return Z; end Big_Sqrt;
关键说明:
Big_Integers.Sqrt:快速获取输入整数的整数平方根近似值,作为牛顿迭代的初始值,比直接用X作为初始值收敛快数倍。- 仅需8次迭代即可收敛到目标精度,进一步减少精度累积的机会。
内容的提问来源于stack exchange,提问作者Henry
相关产品推荐
相关产品推荐

