Java简单公式计算器
最近给公司开发业务代码时,碰到一个场景,简单描述是这样的:
客户要向咱们公司定制一件产品,这个产品呢,有很多属性,那公司得根据这些属性报价呀,怎么报价呢?公司针对某种类型的产品有一个基准价,在同类产品下,某个属性超标了,需要加价,但每一个属性的加价方式都不一样,针对每一家客户加多少价也不一样,每个时间点加价比率也可能不一样,真实情况要比这个复杂不少,这里就不再深入讨论。
那么应对这种需求,我首先想到的关键点是:要把加价这个公式,暴露给实际能控制它的人员去输入,把公式中需要用到的一些参数,以替代符(或者说变量)的方式提供给他们,比如,用a表示基准价,b表示属性超出数值,然后超出部分需要乘以该属性的单价5块钱,那么最终的值就可以写成公式: a + b * 5 ;实际运算的时候,假设a是100,b是20,把他们代替 a和b,公式就成了 100 + 20 * 5,看起来很简单的公式,口算都能算出来,但是正常来讲,公式录入系统,是以字符串的形式保存的,一直到你把真实的值替换到公式里,也是字符串操作,计算机要如何把你这字符串的里的内容正确的计算出来呢?
OK,其实对代码逻辑不是非常好的同学,可以用一些简单的方法,比如,将最终的公式用JavaScript的eval()函数执行一下,就可以得到结果了,这个方法也可以用来在前端验证公式录入正确与否,还有一种方法,把最终的公式直接拼接到SQL语句,对上临时表查一下,如:SELECT 100+20*5 AS result from dual;也可以得到结果,用这两种方法,其实还可能进行更复杂的计算,充分利用JavaScript和sql提供的函数库。
嗯,回到原点,我们现在呢,要在Java服务端实现字符串的公式正确计算,公式虽然简单,但可能每一次要进行几百条公式的计算,也没必要查询几百次数据库,而且这种和金钱相关联的值,如非必要,还是不要抛给前端来替你计算。虽然,公司这边并没有采用我的方案,但是我个人还是把一个简单的公式计算器写了出来,留个思路,以作备用。
简单公式计算器能够满足 加减乘除 和 小括号的运算。
我个人非常建议新手练习一下,基础运用得越扎实,对以后的技术瓶颈突破越好。
代码图上的注释比较少:
粘贴出代码图:
代码来了:
package com.supalle.test; import java.math.BigDecimal;
import java.math.MathContext; /**
* @作者: Supalle
* @时间: 2019/3/8
* @描述: 简单公式计算器
*/
public class Calc { private char[] val; private int len; private int inx; // 构造器,把公式传进去,比如: 100 + 20 * 5 + (1 + 2)
public Calc(String val) {
this.val = val.toCharArray();
len = this.val.length;
inx = 0;
} // 获取计算结果,使用方法其实就是 new Calc("100 + 20 * 5 + (1 + 2)").getResult();就可以得到结果了
public BigDecimal getResult() {
return nextValue(BigDecimal.ZERO, '+');
}
// OK,接下来的两个方法,必须要弄明白,下一个值和下一个参数的区别
// 为什么要获取下一个值,加法、减法、和左小阔号,都需要获取下一个值,因为加法、减法如果碰到乘法、除法,那么运算优先权在右侧,如果碰到左侧小括号,优先权也在右侧,所以要先把右边的值算出来
// 为什么要获取下一个参数,乘法、除法,他们下一个运算符如果不是左侧小括号,那么应该从左往右顺序计算,因此需要直接取到下一个参数进行计算
// 还有一点要值得注意,那就是:在运算时,减法一律替换成加上一个负数,以此来消除实际对一个负数进行运算产生异常,比如 1 * -3,总不能检测到 - 的时候,又去做减法运算吧
// 就讲这么多了,不能理解的同学,再反复推敲几遍
// 获取下一个值,传入第一个参数和第一个参数后的运算符
private BigDecimal nextValue(BigDecimal param1, char operator) {
if (inx < len) {
if (operator == ')') {
return param1;
} if (operator == '+') {
return param1.add(nextValue(nextParam(), inx < len ? val[inx++] : ')'));
} else if (operator == '*') {
return nextValue(param1.multiply(nextParam(), MathContext.DECIMAL128), inx < len ? val[inx++] : ')');
} else if (operator == '/') {
return nextValue(param1.divide(nextParam(), MathContext.DECIMAL128), inx < len ? val[inx++] : ')');
}
}
return param1;
} // 获取下一个参数
private BigDecimal nextParam() { char[] param = new char[len - inx + 1]; int paramInx = 0; while (inx < len) { if (val[inx] == '-') {
if (paramInx == 0) {
param[paramInx++] = val[inx];
param[paramInx++] = '0';
} else {
val[--inx] = '+';
break;
}
} else if (val[inx] == '.' || ((int) val[inx] >= 48 && (int) val[inx] <= 57)) {// 如果是 . 或 0 ~ 9
param[paramInx++] = val[inx];
} else if (val[inx] == '(') {
inx++;
return nextValue(BigDecimal.ZERO, '+');
} else if (((int) val[inx] >= 41 && (int) val[inx] <= 43) || (int) val[inx] == 47) {
break;
} inx++;
} return paramInx > 0 ? new BigDecimal(param, 0, paramInx) : BigDecimal.ZERO;
} }
Java简单公式计算器的更多相关文章
- Java使用BigDecimal精确计算的简单公式计算器
由于工作需要,写了一个使用BigDecimal运算的精确计算的计算器(然后发现其实比不用BigDecimal的并好不到哪里去) 只能做加减乘除 double类型的数字在千万级别的时候会转成科学计数法, ...
- jsp学习---使用jsp和JavaBean实现超简单网页计算器
一.需求 如题,用jsp实现一个超简单的网页计算器. 二.实现 1.效果图 1)初始界面: 2)随便输入两个数进行相乘: 3)当除数为零时提示报错: 2.代码 Calculator.java pack ...
- 教学项目之-通过Python实现简单的计算器
教学项目之-通过Python实现简单的计算器 计算器开发需求 实现加减乘除及拓号优先级解析 用户输入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/ ...
- HDU1237 简单的计算器 【堆】+【逆波兰式】
简单的计算器 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Sub ...
- 多元线性回归----Java简单实现
http://www.cnblogs.com/wzm-xu/p/4062266.html 多元线性回归----Java简单实现 学习Andrew N.g的机器学习课程之后的简单实现. 课程地址:h ...
- 从0到1:使用Caliburn.Micro(WPF和MVVM)开发简单的计算器
从0到1:使用Caliburn.Micro(WPF和MVVM)开发简单的计算器 之前时间一直在使用Caliburn.Micro这种应用了MVVM模式的WPF框架做开发,是时候总结一下了. Calibu ...
- js制作简单的计算器
学着做了一个简单的计算器!记录记录!哈哈 <!DOCTYPE html> <html> <head> <title>简单的计算器</title&g ...
- java简单词法分析器(源码下载)
java简单词法分析器 : http://files.cnblogs.com/files/hujunzheng/%E7%AE%80%E5%8D%95%E8%AF%8D%E6%B3%95%E5%88%8 ...
- 留念 C语言第一课简单的计算器制作
留念 C语言第一课简单的计算器制作 学C语言这么久了. /* 留念 C语言第一课简单的计算器制作 */ #include<stdio.h> #include<stdlib.h ...
随机推荐
- Python正则表达式进阶-零宽断言
1. 什么是零宽断言 有时候在使用正则表达式做匹配的时候,我们希望匹配一个字符串,这个字符串的前面或后面需要是特定的内容,但我们又不想要前面或后面的这个特定的内容,这时候就需要零宽断言的帮助了.所谓零 ...
- 设置windows服务依赖项
场景还原:python2.7开发的项目,制作成了windows服务,随系统启动.系统重启后发现服务未能自动启动,检查事件查看器日志发现服务先于Mysql数据库服务启动,由于服务中必须对MySQL进行访 ...
- HTTP Post之multipart/form-data和application/x-www-form-urlencoded
关于HttpPost,有这样两种可Post的数据载体,分别是MultipartEntity和UrlEncodedFormEntity,对这两者的共性和异性做如下解释和备忘: 共性: 1.都属于HTTP ...
- 每日一问:浅谈 onAttachedToWindow 和 onDetachedFromWindow
基本上所有 Android 开发都会接触到 onCreate().onDestory().onStart().onStop() 等这些生命周期方法,但却不是所有人都会去关注到 onAttachXXX( ...
- python算法与数据结构-循环链表(39)
一.循环链表的介绍 上一篇我们已经讲过单链表,本篇给大家讲解循单链表的一个变形是单向循环链表,链表中最后一个节点的next域不再为None,而是指向链表的头节点,其基本操作和单链表思路一样. 常用的操 ...
- 【转载】Spring Boot引起的“堆外内存泄漏”排查及经验总结
背景 为了更好地实现对项目的管理,我们将组内一个项目迁移到MDP框架(基于Spring Boot),随后我们就发现系统会频繁报出Swap区域使用量过高的异常.笔者被叫去帮忙查看原因,发现配置了4G堆内 ...
- vue.js实现单选框、复选框和下拉框
Vue.js可以很方便的实现数据双向绑定,所以在处理表单,人机交互方面具有很大的优势.下边以单选框.复选框和下拉框为例介绍他们在HTML和Vue.js中的具体实现方式. 一.单选框 在传统的HTM ...
- 拉格朗日乘子法 - KKT条件 - 对偶问题
接下来准备写支持向量机,然而支持向量机和其他算法相比牵涉较多的数学知识,其中首当其冲的就是标题中的拉格朗日乘子法.KKT条件和对偶问题,所以本篇先作个铺垫. 大部分机器学习算法最后都可归结为最优化问题 ...
- 《大型网站系统与Java中间件》读书笔记 (中)
前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 回顾上一篇: <大型网站系统与Java中间件& ...
- C++程序设计1(侯捷video 7-13)
一.Big three(拷贝构造.拷贝赋值.析构函数)(video7) Big three指三个特殊函数,分别是拷贝构造函数.拷贝赋值和析构函数. 什么时候需要拷贝构造.拷贝赋值.析构函数: 当类中 ...