You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 16:00:32