// Package decimal 提供金额与油耗计算相关的精度保护。 // // 计算原则(严格按 FuelLog_PLAN.md §6): // - 实际油价 = 总金额 / 加油量 // - 行驶里程 = 本次里程 - 上一次有效里程 // - 百公里油耗 = 加油量 / 行驶里程 * 100 // - 每公里燃油成本 = 燃油费用 / 行驶里程 // // 所有除法走 shopspring/decimal,避免 float64 在金额上累计误差。 package decimal import ( "github.com/shopspring/decimal" ) // PricePerLiter 计算实际油价(元/升)。 // 若 liters <= 0,返回零值;调用方应保证 liters > 0(后端已强校验)。 func PricePerLiter(totalAmount, liters float64) float64 { if liters <= 0 { return 0 } t := decimal.NewFromFloat(totalAmount) l := decimal.NewFromFloat(liters) return t.Div(l).Round(4).InexactFloat64() } // ConsumptionL100km 计算百公里油耗(升/100 公里)。 // 若 mileage <= 0,返回 0;调用方需保证 mileage > 0(半箱油场景应在 service 跳过)。 func ConsumptionL100km(liters, mileage float64) float64 { if mileage <= 0 { return 0 } l := decimal.NewFromFloat(liters) m := decimal.NewFromFloat(mileage) // L/100km = liters / mileage * 100 return l.Div(m).Mul(decimal.NewFromInt(100)).Round(2).InexactFloat64() } // CostPerKm 计算每公里燃油成本(元/公里)。 // 若 mileage <= 0,返回 0。 func CostPerKm(totalAmount, mileage float64) float64 { if mileage <= 0 { return 0 } t := decimal.NewFromFloat(totalAmount) m := decimal.NewFromFloat(mileage) return t.Div(m).Round(4).InexactFloat64() } // Mileage 计算两次加油之间的行驶里程。负数 / 零视为无效,返回 0。 func Mileage(current, previous float64) float64 { d := current - previous if d <= 0 { return 0 } return d } // AvgFloat64 返回一组数的算术平均值,空切片返回 0。 func AvgFloat64(xs []float64) float64 { if len(xs) == 0 { return 0 } sum := decimal.Zero for _, x := range xs { sum = sum.Add(decimal.NewFromFloat(x)) } return sum.Div(decimal.NewFromInt(int64(len(xs)))).Round(2).InexactFloat64() }