精度问题:

我们知道java中直接使用float和double参与的计算都可能会产生精度问题,比如0.1+0.3、1.0-0.9 等。所以一般财务系统,都会使用BigDecimal进行加减乘除。 在调研Fel过程中,发现Fel里进行计算都是使用浮点数加减乘除的,所以不可避免的会产生精度问题。

Case+源码分析:

加法 Case:

FelEngine fel = new FelEngineImpl();
Object result = fel.eval("0.1+0.2");
System.out.println(result);





源码分析:

简单的来说,Fel首先经过词法解析器将表达式解析成FelNode实例,FelNode包含表达式子节点(比如+号、0.1等)和表达式解析器,解析器对应的有com.greenpineyu.fel.function.operator.Add、ccom.greenpineyu.fel.function.operator.Sub、com.greenpineyu.fel.function.operator.Mul、com.greenpineyu.fel.function.operator.Div等各种解析器(详见com.greenpineyu.fel.function.operator下的类),具体的表达式运算结果是由这些解析器计算的。具体到方法又是由com.greenpineyu.fel.function.operator.Add#call计算的。

public Object call(FelNode node, FelContext context) {
Object returnMe = null;
for (Iterator<FelNode> iterator = node.getChildren().iterator(); iterator.hasNext();) {
Object child = iterator.next();
if (child instanceof FelNode) {
FelNode childNode = (FelNode) child;
child = childNode.eval(context);
}
if (child instanceof String) {
if (returnMe == null) {
returnMe = child;
continue;
}
returnMe = returnMe + (String) child;
}
if (child instanceof Number) {
if (returnMe == null) {
returnMe = child;
continue;
}
Number value = (Number) child;
if (returnMe instanceof Number) {
Number r = (Number) returnMe;
// 注意这里:是直接使用转成double进行加减的。
returnMe = toDouble(r) + toDouble(value);
}else if(returnMe instanceof String){
String r = (String) returnMe;
returnMe=r+value;
}
}
}
if(returnMe instanceof Number){
return NumberUtil.parseNumber(returnMe.toString());
}
return returnMe;
} /**
* 将Number转换成double
* @param number
* @return
*/
public static double toDouble(Number number){
if(number instanceof Float){
//float转double时,会出现精度问题。"(double)1.1f"的值类似于1.1000000476837158),
//使用 Double.parseDouble(number.toString());则不会出现问题。
return Double.parseDouble(number.toString());
}
return number.doubleValue();
}

通过上面的returnMe = toDouble(r) + toDouble(value); 代码片段,我们就知道Fel是拿double进行加法操作的,这样某些情况下就会产生精度问题。

其他运算操作同之。

解决办法:

避免使用浮点数进行数值计算,可以将操作数乘以10的某个倍数,将浮点数转成整数。至于从整数再转成浮点数就可以使用BigDecimal了。其实,一个好的财务系统都是不会存储和使用浮点数的,都是转成整数,只有在进行页面显示的时候才处理回浮点数。

Fel表达式使用过程中需要注意的问题的更多相关文章

  1. lua解析脚本过程中的关键数据结构介绍

    在这一篇文章中我先来介绍一下lua解析一个脚本文件时要用到的一些关键的数据结构,为将来的一系列代码分析打下一个良好的基础.在整个过程中,比较重要的几个源码文件分别是:llex.h,lparse.h.l ...

  2. ios逆向过程中lldb调试技巧

    在ios逆向过程中,善于运用lldb,会给逆向带来很大的方便 一般的命令: 1.image list -o -f  看看各个模块在内存中的基址 2.register read r0  读取寄存器r0的 ...

  3. react使用过程中常见问题

    目录 一.减小输入字符数 二.用props.children来引用位于前置标签和后置标签之间的内容 三.创建组件两条主要的途径 四.JSX属性采用驼峰式的大小写规则(即‘onClick’而非‘oncl ...

  4. <转>lua解析脚本过程中的关键数据结构介绍

    在这一篇文章中我先来介绍一下lua解析一个脚本文件时要用到的一些关键的数据结构,为将来的一系列代码分析打下一个良好的基础.在整个过程中,比较重要的几个源码文件分别是:llex.h,lparse.h.l ...

  5. Sybase IQ使用过程中注意事项

    Sybase IQ使用过程中注意事项 1,字母大小写比对不敏感,也就是在值比对判断时大小写字母都一样; 2,等值,或<>判断,系统默认对等式两边比对值去右边空格再进行比较: 3,GROUP ...

  6. 计算后缀表达式的过程(C#)

    计算后缀表达式的过程是一个很好玩的过程,而且很简单哦!这里呢,有个计算的技巧,就是:遇到数字直接入栈,遇到运算符就计算! 后缀表达式也叫逆波兰表达式,求值过程可以用到栈来辅助存储: 假定待求值的后缀表 ...

  7. this在方法赋值过程中无法保持(隐式丢失)

    在看<高级程序设计>(我的红宝书) P.183页时遇到下面一个问题 var name = "77"; var obj = { name: "88", ...

  8. 转:Oracle中SQL语句执行过程中

    Oracle中SQL语句执行过程中,Oracle内部解析原理如下: 1.当一用户第一次提交一个SQL表达式时,Oracle会将这SQL进行Hard parse,这过程有点像程序编译,检查语法.表名.字 ...

  9. springfox-swagger原理解析与使用过程中遇到的坑

    swagger简介 swagger确实是个好东西,可以跟据业务代码自动生成相关的api接口文档,尤其用于restful风格中的项目,开发人员几乎可以不用专门去维护rest api,这个框架可以自动为你 ...

随机推荐

  1. BZOJ2821:作诗——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=2821 问题描述 神犇SJY虐完HEOI之后给傻×LYD出了一题: SHY是T国的公主,平时的一大爱好 ...

  2. 洛谷 P1516 青蛙的约会 解题报告

    P1516 青蛙的约会 题目描述 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件 ...

  3. AOJ.866 飞越原野 (三维BFS)

    AOJ.866 飞越原野 (三维BFS) 题意分析 点我挑战题目 相比于普通的BFS,要多一维来记录当前剩余的体力.而且还要额外的一层循环来处理,飞过的路程. 代码总览 #include <io ...

  4. (ex)BSGS题表

    学了一下BSGS大概知道他是什么了,但是并没有做什么难题,所以也就会个板子.普通的BSGS,我还是比较理解的,然而exBSGS我却只理解个大概,也许还会个板子......(这个东西好像都会有一群恶心的 ...

  5. 全面解析JavaScript的Backbone.js框架中的Router路由

    这篇文章主要介绍了Backbone.js框架中的Router路由功能,Router在Backbone中相当于一个MVC框架中的Controller控制器功能,需要的朋友可以参考下. Backbone ...

  6. 【套题】qbxt国庆刷题班D2

    D2 今天的题感觉还是好妙的 T1 传送门 Description 现在有一张\(n\)个节点\(m\)条边的无向连通图\(G=(V,E)\),满足这张图中不存在长度大于等于3的环且图中没有重边和自环 ...

  7. [10.18模拟赛] 序列 (DP)

    [10.18模拟赛] 序列 题目描述 山山有一个整数序列s1,s2,-,sn,其中1≤si≤k. 求出有多少个准确移除m个元素后不同的序列.答案模(1e9+7) 输入 输入包括几个测试用例,并且由文件 ...

  8. CodeVS 1017 DP

    1017 乘积最大 2000年NOIP全国联赛普及组NOIP全国联赛提高组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描 ...

  9. postman ubuntu 14.04 安装

    https://jingyan.baidu.com/album/e3c78d649735d63c4c85f5e5.html?picindex=1 实测有效---

  10. LCD显示屏原理与应用

    1.什么是LCD? (1)LCD(Liquid Crystal Display)俗称液晶.(2)液晶是一种材料,液晶这种材料具有一种特点:可以在电信号的驱动下液晶分子进行旋转,旋转时会影响透光性,因此 ...