当前位置:首页 > 文章列表 > Golang > Go教程 > Go big.Rat 怎样保存精确小数计算

Go big.Rat 怎样保存精确小数计算

来源:17golang原创 2026-10-14 19:32:03 0浏览 收藏

Go big.Rat 保存精确小数计算的做法是:从十进制字符串调用 SetString,运算保持在 Rat 中,存档使用 RatString,读回再用 SetString。FloatString(2) 适合显示两位小数,却可能舍入,不能普遍代替精确存档。

输入小数先保留原始字符串

假设一个换算功能收到字符串“10.25”和“0.15”,需要保留乘法结果,而页面只显示两位。这里的技术目标是让保存值保持 1.5375,不提前变成 1.54;示例不代表真实结算规则。

字符串是数值来源的一部分。若先 ParseFloat,再 SetFloat64,Rat 保存的是那个浮点数本身的精确值,而不是自动恢复原始十进制。例如通常的 float64 0.1 不是数学意义上的 1/10,换成有理数不会抹掉前面的表示误差。

官方接口文档:https://pkg.go.dev/math/big#Rat。下面围绕字符串与 Rat 的边界组织实现,不展开数据库、货币单位或结算制度。

把解析失败挡在运算之前

SetString 接受的格式比普通小数输入宽,包含分数和带指数的数字。库能解析不代表业务应该接受。演示中的 parseDecimal 先限制为带可选正负号的普通十进制,最多64字节,不接受空白、分数、指数和千位分隔符;具体项目还应按需求规定数值范围和小数位数。

必须检查返回的 ok。解析失败时返回 nil,接收者的内容不能作为有效值使用。不要用旧对象反复尝试解析后,失败仍继续计算,也不要默默把非法输入替换成零。分数存档与普通小数输入是两种格式,恢复入口不能错误地套用这个仅允许十进制的正则。

字符串输入约束与精确有理数模型的静态关联
图1:原创静态结构说明图。输入预算和十进制格式约束属于输入层;SetString 与 Rat 属于数值层,Rat 的值由分子和分母表达,不保留原始排版。

用 Rat 保存精确值而不是显示位数

Rat 是有理数,不是自动附带“保留两位”的十进制字段。它表达分子与分母的比值:有限小数能精确表达,1/3 这样的循环小数也能精确保存在有理数模型里。它不保留原输入中的尾随零;“1.20”和“1.2”具有相同数值,若需要保存原排版,应另存原始字符串或业务尺度。

math/big 运算写入接收者。使用 new(big.Rat).Mul(amount, factor) 得到独立结果,输入保持不变;若把 amount 自己当接收者,它的值就会被覆盖。精确计算不是无限资源,输入长度、运算规模和显示位数都需要预算。

保存分数字符串并恢复计算

下面完整 main.go 展示输入解析、乘法、保存和恢复;不涉及文件或数据库写入,saved 就是待交给存储层的字符串。

package main

import (
    "fmt"
    "log"
    "math/big"
    "regexp"
)

// 示例仅收普通十进制,拒绝分数、指数、空白和额外字符。
var decimal = regexp.MustCompile(`^[+-]?[0-9]+(\.[0-9]+)?$`)

func parseDecimal(s string) (*big.Rat, error) {
    // 长度64是演示输入预算,不是通用金额业务规则。
    if len(s) == 0 || len(s) > 64 || !decimal.MatchString(s) {
        return nil, fmt.Errorf("小数字符串格式或长度不符合要求")
    }
    r, ok := new(big.Rat).SetString(s)
    if !ok {
        // 失败接收者的内容不可继续使用。
        return nil, fmt.Errorf("小数字符串无法解析")
    }
    return r, nil
}

func main() {
    amount, err := parseDecimal("10.25")
    if err != nil { log.Fatal(err) }
    factor, err := parseDecimal("0.15")
    if err != nil { log.Fatal(err) }

    // 独立接收者保留输入对象;示例只是十进制乘法。
    result := new(big.Rat).Mul(amount, factor)
    saved := result.RatString()
    restored, ok := new(big.Rat).SetString(saved)
    if !ok {
        log.Fatal("保存字符串恢复失败")
    }
    // 字符串显示可舍入,但保存和恢复仍保留精确数值。
    fmt.Println("保存值:", saved)
    fmt.Println("显示值:", result.FloatString(2))
    fmt.Println("恢复相等:", restored.Cmp(result) == 0)

    // 循环小数也能以有理数形式无损保存。
    third := big.NewRat(1, 3)
    fmt.Println("三分之一保存:", third.RatString())
    fmt.Println("三分之一显示:", third.FloatString(2))
}

按数学计算推导,保存值为 123/80,显示值为 1.54,恢复比较为 true;三分之一保存为 1/3,显示为 0.33。这些是示例预期,不是本机运行记录。真正存档时字段类型应能保留整个字符串,不能让接口再把它转成 float64。

RatString 在分母为1时可以只输出整数;String 则总是 a/b 形式。选定一种作为接口约定,保存时注明是有理数字符串,避免调用方把“123/80”当作十进制数解析。读回外部存档也要限制长度并检查 SetString 成功,不能因来源叫“存档”而完全信任。

Rat 精确存档与 FloatString 显示的边界
图2:原创静态依赖说明图。RatString 关联精确存档,SetString 关联恢复对象,Cmp 比较数值;FloatString 属于显示边界,不是无损格式。连线不表示执行时序。

别把显示舍入当作精确结果

用途采用方式保留什么
继续精确计算Rat 运算有理数值
无损存档RatString 后 SetString完整数值,不保留原排版
固定小数显示FloatString(位数)舍入后的显示文本
原输入格式另存输入字符串尾随零等文字信息

FloatString 按小数位数生成文本,末位按最近值舍入,恰好一半时远离零,不是默认银行家舍入。给 1/3 输出两位只能得到近似显示;把“0.33”再解析回 Rat,得到的是 33/100,不再是 1/3。Rat 本身不会因为调用 FloatString 而变成舍入后的值。

因此原场景的取舍很明确:存档用精确字符串,显示独立处理。若业务明确要求某一环节量化到固定尺度,需要另外定义舍入时点和规则,不能把显示函数直接当成所有场景的处理规范。

结束计算时保持对象所有权清楚

Rat 对象不支持结构体浅拷贝。需要独立副本时用 new(big.Rat).Set(original),不要写 copied := *original 再分别修改。多个 goroutine 共享可变 Rat 时仍需自己的同步和所有权规则;精确算术不等于并发修改安全。

这些对象没有文件句柄可关闭。局部计算结束后,不再持有临时对象引用即可让垃圾回收管理内存;不要在 long-lived 容器里无界保存每次计算的临时对象。这里的生命周期管理是输入、结果、存档文本各自负责,不是增加一个清理 API。

能用 FloatString 保存全部精度吗?

对任意 Rat 不能保证。循环小数没有有限位数的无损十进制表示,优先保存分数字符串。

为什么 1.200 的三个小数位不见了?

Rat 保存数值,不保存原字符串尺度。需要原样显示时另存输入文本。

解析失败后可以继续使用接收者吗?

不能依赖其值,必须停止这一条输入的计算并返回错误。除法还应另行检查除数为零,本文没有实现通用除法接口。

字符串转换实现可对照 https://go.dev/src/math/big/ratconv.go。完整方案的关键是让字符串保持十进制来源,让 Rat 保持精确计算,让存档和显示承担不同职责。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go 怎样拆分浮点数的尾数和指数Go 怎样拆分浮点数的尾数和指数
上一篇
Go 怎样拆分浮点数的尾数和指数
Go filepath.Rel 怎样计算两个路径的相对关系
下一篇
Go filepath.Rel 怎样计算两个路径的相对关系
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    473次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    531次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    551次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    503次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    318次使用