CEILING 函数可以将参数 number 向上/向下舍入为最接近的指定基数的倍数。
CEILING(number, significance)
其中各参数的含义如下:
number: 必需。 要舍入的值。
significance: 必需。 要舍入到的倍数。
对于不同符号的参数搭配,具体计算规则如下:
当 number 为正时,不管 significance 为正或为负,对值按远离 0 的方向进行向上舍入;
当 number 为负,significance 为正时,对值按朝向 0 的方向进行向上舍入;
当 number 和 significance 都为负时,对值按远离 0 的方向进行向下舍入。
公式 | 说明 | 结果 |
CEILING(10, 3) | 将 10 向上舍入到最接近的 3 的倍数 | 12 |
CEILING(10, -3) | 将 10 向上舍入到最接近的 -3 的倍数 | 12 |
CEILING(-10, 3) | 将 -10 向上舍入到最接近的 3 的倍数 | -9 |
CEILING(-10, -3) | 将 -10 向下舍入到最接近的 -3 的倍数 | -12 |
首先我们在function包下创建math包,在math包下创建CeilingFunction类,代码如下:
package com.ql.util.express.self.combat.function.math;
import com.ql.util.express.Operator;
import com.ql.util.express.self.combat.exception.FormulaException;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* 类描述: CEILING函数
*
* @author admin
* @version 1.0.0
* @date 2023/11/23 9:31
*/
public class CeilingFunction extends Operator {
public CeilingFunction(String name) {
this.name = name;
}
@Override
public Object executeInner(Object[] objects) throws Exception {
// 参数校验
if (objects.length != 2) {
throw new FormulaException("操作数异常");
}
Object result = 0;
// 考虑精度问题
if (isPrecise) {
BigDecimal number = new BigDecimal(objects[0].toString());
BigDecimal multiple = new BigDecimal(objects[1].toString());
result = precise(number,multiple);
} else {
// 根据objects数组中的第一个数,无论什么数据类型,一律按照double处理
double n = Double.parseDouble(objects[0].toString());
double s = Double.parseDouble(objects[1].toString());
result = ceiling(n,s);
}
return result;
}
private static double ceiling(double n, double s) {
if (n>0.0D && s<0.0D) {
s = Math.abs(s);
}
return n > 0.0D && s < 0.0D?0.0D / 0.0:(n != 0.0D && s != 0.0D?Math.ceil(n / s) * s:0.0D);
}
private static BigDecimal precise(BigDecimal number, BigDecimal multiple) {
BigDecimal zero = BigDecimal.ZERO;
int comparisonResult = multiple.compareTo(zero);
int flag = number.compareTo(zero);
BigDecimal roundedNumber = BigDecimal.ZERO;
if (flag >= 0 && comparisonResult >=0) {
roundedNumber = number.divide(multiple, 0, RoundingMode.CEILING).multiply(multiple);
} else if (flag < 0 && comparisonResult >=0) {
roundedNumber = number.divide(multiple, 0,RoundingMode.CEILING).multiply(multiple);
} else if (flag >= 0 && comparisonResult < 0) {
roundedNumber = number.divide(multiple, 0,RoundingMode.FLOOR).multiply(multiple);
}
else if (flag < 0 && comparisonResult < 0) {
roundedNumber = number.divide(multiple, 0).multiply(multiple);
}
return roundedNumber;
}
}
把CeilingFunction类注册到公式函数入口类中,代码如下:
package com.ql.util.express.self.combat.ext;
import com.ql.util.express.ExpressRunner;
import com.ql.util.express.IExpressResourceLoader;
import com.ql.util.express.parse.NodeTypeManager;
import com.ql.util.express.self.combat.function.logic.*;
import com.ql.util.express.self.combat.function.math.AbsFunction;
import com.ql.util.express.self.combat.function.math.AvgFunction;
import com.ql.util.express.self.combat.function.math.CeilingFunction;
/**
* 类描述: 仿简道云公式函数实战入口类
*
* @author admin
* @version 1.0.0
* @date 2023/11/21 15:29
*/
public class FormulaRunner extends ExpressRunner {
public FormulaRunner() {
super();
}
public FormulaRunner(boolean isPrecise, boolean isTrace) {
super(isPrecise,isTrace);
}
public FormulaRunner(boolean isPrecise, boolean isStrace, NodeTypeManager nodeTypeManager) {
super(isPrecise,isStrace,nodeTypeManager);
}
public FormulaRunner(boolean isPrecise, boolean isTrace, IExpressResourceLoader iExpressResourceLoader, NodeTypeManager nodeTypeManager) {
super(isPrecise,isTrace,iExpressResourceLoader,nodeTypeManager);
}
@Override
public void addSystemFunctions() {
// ExpressRunner 的内部系统函数
super.addSystemFunctions();
// 扩展公式函数
this.customFunction();
}
/***
* 自定义公式函数
*/
public void customFunction() {
// 逻辑公式函数
this.addLogicFunction();
// 数学公式函数
this.addMathFunction();
}
public void addLogicFunction() {
// AND函数
this.addFunction("AND",new AndFunction("AND"));
// IF函数
this.addFunction("IF",new IfFunction("IF"));
// IFS函数
this.addFunction("IFS",new IfsFunction("IFS"));
// XOR函数
this.addFunction("XOR",new XorFunction("XOR"));
// TRUE函数
this.addFunction("TRUE",new TrueFunction("TRUE"));
// FALSE函数
this.addFunction("FALSE",new FalseFunction("FALSE"));
// NOT函数
this.addFunction("NOT",new NotFunction("NOT"));
// OR函数
this.addFunction("OR",new OrFunction("OR"));
}
public void addMathFunction() {
// ABS函数
this.addFunction("ABS",new AbsFunction("ABS"));
// AVERAGE函数
this.addFunction("AVERAGE",new AvgFunction("AVERAGE"));
// CEILING函数
this.addFunction("CEILING",new CeilingFunction("CEILING"));
}
}
创建测试用例
package com.ql.util.express.self.combat;
import com.ql.util.express.DefaultContext;
import com.ql.util.express.self.combat.ext.FormulaRunner;
import org.junit.Test;
/**
* 类描述: 实战测试类
*
* @author admin
* @version 1.0.0
* @date 2023/11/21 15:45
*/
public class CombatTest {
@Test
public void CEILING() throws Exception{
FormulaRunner formulaRunner = new FormulaRunner(true,true);
// 创建上下文
DefaultContext<String, Object> context = new DefaultContext<>();
String express = "CEILING(a,b)";
// context.put("a",10);
// context.put("b",3);
// System.out.println(12);
// context.put("a",10);
// context.put("b",-3);
// System.out.println(12);
// context.put("a",-10);
// context.put("b",3);
// System.out.println(-9);
//
context.put("a",-10);
context.put("b",-3);
Object object = formulaRunner.execute(express, context, null, true, true);
System.out.println(object);
}
}
运行结果