汽车油耗计算逻辑

PS:本次油耗计算,是基于对标产品小熊油耗进行测试研究输出的实现逻辑。

小熊油耗算法测试:

加油量

当前总公里

是否灯亮

是否跳枪

是否漏计上次

油耗(升/百公里)

算法

公式

1

2

100

y

y

n

0

2

2

200

y

y

n

2

1

2/(200-100)*100

3

1.8

280

y

n

n

2.5

2

2/(280-200)*100

4

1.6

340

n

n

n

0

5

1.6

400

n

n

n

0

6

1.8

480

y

n

n

2.5

4

(1.8+1.6+1.6)/(480-280)*100

7

1.6

560

n

n

n

0

8

1.8

640

n

y

n

2.32

3

(1.8+1.6+1.6+1.8+1.6+1.8)/(640-200)*100 

···

9

1.8

720

n

y

y

0

1.8/(720-640)*100

10

1.8

800

n

y

n

2.25

1

1.8/(800-720)*100

1

35

100

y

y

y

0

2

35

200

y

y

y

2.73

3

40

300

y

y

y

3.12

4

36

400

2.81

5

55

500

4.29

6

油耗计算业务流程图:(程序参考)

 

程序实现:

package com.xiulian.open;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * 程序实现油耗算法
 * 注意:
 * 1、测试中的历史数据应以数据库为准,当前数据以当前输入的数据为准
 * 2、static方法方便测试,实际程序应去掉
 */
public class TestOilConsumptionResult {

    public static void main(String[] args) {
//        OilRecord currentRecord = new OilRecord(1, 2, 100, 0, true, true, true);
//        OilRecord currentRecord = new OilRecord(2, 2, 200, 0, true, true, true);
//        OilRecord currentRecord = new OilRecord(3, 1.8, 280, 0, false, true, true);
//        OilRecord currentRecord = new OilRecord(4, 1.6, 340, 0, false, false, true);
//        OilRecord currentRecord = new OilRecord(5, 1.6, 400, 0, false, false, true);
//        OilRecord currentRecord = new OilRecord(6, 1.8, 480, 0, false, true, true);
//        OilRecord currentRecord = new OilRecord(7, 1.6, 560, 0, false, false, true);
//        OilRecord currentRecord = new OilRecord(8, 1.8, 640, 0, true, false, true);
//        //···中间漏记
//        OilRecord currentRecord = new OilRecord(9, 1.8, 720, 0, true, false, false);
        OilRecord currentRecord = new OilRecord(10, 1.8, 800, 0, true, false, true);

        //计算逻辑
        double oilConsumptionResult = oilConsumptionResultLogic(currentRecord);
        System.out.println("油耗结果:" + oilConsumptionResult);

    }


    private static List<OilRecord> getHistoryRecords() {
        List<OilRecord> historyRecordList = new ArrayList<>();

        historyRecordList.add(new OilRecord(1, 2, 100, 0, true, true, true));
        historyRecordList.add(new OilRecord(2, 2, 200, 0, true, true, true));
        historyRecordList.add(new OilRecord(3, 1.8, 280, 0, false, true, true));
        historyRecordList.add(new OilRecord(4, 1.6, 340, 0, false, false, true));
        historyRecordList.add(new OilRecord(5, 1.6, 400, 0, false, false, true));
        historyRecordList.add(new OilRecord(6, 1.8, 480, 0, false, true, true));
        historyRecordList.add(new OilRecord(7, 1.6, 560, 0, false, false, true));
        historyRecordList.add(new OilRecord(8, 1.8, 640, 0, true, false, true));
//        //···中间漏记
        historyRecordList.add(new OilRecord(9, 1.8, 720, 0, true, false, false));
//        historyRecordList.add(new OilRecord(10, 1.8, 800, 0, true, false, true));

        return historyRecordList;
    }


    /**
     * 业务逻辑方法
     * @param currentRecord
     * @return
     */
    private static double oilConsumptionResultLogic(OilRecord currentRecord) {

        if (currentRecord.isForgetLastTime()) {

            if (currentRecord.isJumpGun()) {

                OilRecordLogic lastJumpGunData = getLastJumpGunRecord(currentRecord);
                if (null == lastJumpGunData) {

                    return noJumpGunLogic(currentRecord);

                } else {

                    if (currentRecord.isOilLampWarning()) {

                        OilRecordLogic lastOilLampWarningData = getLastOilLampWarningData(currentRecord);
                        if (null == lastOilLampWarningData) {

                            return selectJumpGunAlgorithm(lastJumpGunData);

                        } else {

                            if (lastJumpGunData.getSpanNum() <= lastOilLampWarningData.getSpanNum()) {

                                return selectJumpGunAlgorithm(lastJumpGunData);

                            } else {

                                return selectOilLampWarningAlgorithm(lastOilLampWarningData);

                            }

                        }

                    } else {

                        return selectJumpGunAlgorithm(lastJumpGunData);

                    }

                }


            } else {

                return noJumpGunLogic(currentRecord);

            }

        } else {

            return 0;

        }

    }

    /**
     * 没跳枪逻辑
     *
     * @param currentRecord
     * @return
     */
    private static double noJumpGunLogic(OilRecord currentRecord) {
        if (currentRecord.isOilLampWarning()) {

            OilRecordLogic lastOilLampWarningData = getLastOilLampWarningData(currentRecord);
            if (null == lastOilLampWarningData) {
                return 0;
            } else {

                return selectOilLampWarningAlgorithm(lastOilLampWarningData);

            }

        } else {
            return 0;
        }
    }

    /**
     * 跳枪,选择算法
     *
     * @param lastJumpGunData
     * @return
     */
    private static double selectJumpGunAlgorithm(OilRecordLogic lastJumpGunData) {
        if (lastJumpGunData.getSpanNum() > 1) {
            //算法3
            return algorithm3(lastJumpGunData.getSpanAddOilNum(), lastJumpGunData.getSpanMileage());
        } else {
            //算法1
            return algorithm1(lastJumpGunData.getSpanAddOilNum(), lastJumpGunData.getSpanMileage());
        }
    }

    /**
     * 灯亮,选择算法
     *
     * @param lastOilLampWarningData
     * @return
     */
    private static double selectOilLampWarningAlgorithm(OilRecordLogic lastOilLampWarningData) {
        if (lastOilLampWarningData.getSpanNum() > 1) {
            //算法4
            return algorithm4(lastOilLampWarningData.getSpanAddOilNum(), lastOilLampWarningData.getSpanMileage());
        } else {
            //算法2
            return algorithm2(lastOilLampWarningData.getSpanAddOilNum(), lastOilLampWarningData.getSpanMileage());
        }
    }

    /**
     * 获取上次跳枪数据
     *
     * @return
     */
    private static OilRecordLogic getLastJumpGunRecord(OilRecord currentRecord) {
        OilRecordLogic oilRecordLogic = new OilRecordLogic();
        int spanNum = 0;//跨度数量
        double spanAddOilNum = 0;//阶段油耗

        List<OilRecord> historyRecordList = getHistoryRecords();//TODO 模拟数据,真实应从数据库获取
        int historyRecordListSize = historyRecordList.size();
        for (int i = historyRecordListSize - 1; i >= 0; i--) {
            OilRecord oilRecord = historyRecordList.get(i);

            spanNum++;

            if (oilRecord.isJumpGun) {
                oilRecordLogic.setOilRecord(oilRecord);
                oilRecordLogic.setSpanNum(spanNum);
                oilRecordLogic.setSpanMileage(currentRecord.getTotalMileage() - oilRecord.getTotalMileage());
                oilRecordLogic.setSpanAddOilNum(spanAddOilNum+currentRecord.getAddOilNum());
                return oilRecordLogic;
            }

            spanAddOilNum += oilRecord.getAddOilNum();//跳枪,阶段油量,含后、不含前
        }
        return null;
    }

    /**
     * 获取上次灯亮数据
     *
     * @return
     */
    private static OilRecordLogic getLastOilLampWarningData(OilRecord currentRecord) {
        OilRecordLogic oilRecordLogic = new OilRecordLogic();
        int spanNum = 0;//跨度数量
        double spanAddOilNum = 0;//阶段油耗

        List<OilRecord> historyRecordList = getHistoryRecords();//TODO 模拟数据,真实应从数据库获取
        int historyRecordListSize = historyRecordList.size();
        for (int i = historyRecordListSize - 1; i >= 0; i--) {
            OilRecord oilRecord = historyRecordList.get(i);

            spanNum++;
            spanAddOilNum += oilRecord.getAddOilNum();//灯亮,阶段油量,不含后、含前

            if (oilRecord.isOilLampWarning) {
                oilRecordLogic.setOilRecord(oilRecord);
                oilRecordLogic.setSpanNum(spanNum);
                oilRecordLogic.setSpanMileage(currentRecord.getTotalMileage() - oilRecord.getTotalMileage());
                oilRecordLogic.setSpanAddOilNum(spanAddOilNum);
                return oilRecordLogic;
            }
        }
        return null;
    }

    /**
     * 算法1:计算两次跳枪
     *
     * @param addOilNumNext
     * @param mileageNext
     * @return
     */
    private static double algorithm1(double addOilNumNext, double mileageNext) {
        //油耗 = 第二次加油量/这两次记录之间的行驶里程
        double oilConsumption = addOilNumNext / mileageNext * 100;
        return Double.valueOf(new DecimalFormat("#.00").format(oilConsumption));//保留两位小数点(四舍五入)
    }

    /**
     * 算法2:计算两次灯亮
     *
     * @param addOilNumLast
     * @param mileageLast
     * @return
     */
    private static double algorithm2(double addOilNumLast, double mileageLast) {
        //油耗 = 第一次加油量/这两次记录之间的行驶里程
        double oilConsumption = addOilNumLast / mileageLast * 100;
        return Double.valueOf(new DecimalFormat("#.00").format(oilConsumption));//保留两位小数点(四舍五入)
    }

    /**
     * 算法3:计算两点跳枪
     *
     * @param spanOilConsumptionNext
     * @param spanMileageNext
     * @return
     */
    private static double algorithm3(double spanOilConsumptionNext, double spanMileageNext) {
        //阶段油耗 = 上一次加满(不含)到下一次加满(含)之间加油总量/上一次加满到下一次加满之间的里程
        double oilConsumptionCalculate = spanOilConsumptionNext / spanMileageNext * 100;
        return Double.valueOf(new DecimalFormat("#.00").format(oilConsumptionCalculate));
    }

    /**
     * 算法4:计算两点灯亮
     *
     * @param spanOilConsumptionLast
     * @param spanMileageLast
     * @return
     */
    private static double algorithm4(double spanOilConsumptionLast, double spanMileageLast) {
        //阶段油耗 = 上一次油灯亮(含)到下一次油灯亮(不含)之间加油总量/上一次油灯亮到下一次油灯亮之间的里程。
        double oilConsumptionCalculate = spanOilConsumptionLast / spanMileageLast * 100;
        return Double.valueOf(new DecimalFormat("#.00").format(oilConsumptionCalculate));
    }

    private static class OilRecordLogic {
        private OilRecord OilRecord;//加油记录
        private int spanNum;//跨度数量
        private double spanMileage;//阶段里程
        private double spanAddOilNum;//阶段油耗

        public TestOilConsumptionResult.OilRecord getOilRecord() {
            return OilRecord;
        }

        public void setOilRecord(TestOilConsumptionResult.OilRecord oilRecord) {
            OilRecord = oilRecord;
        }

        public int getSpanNum() {
            return spanNum;
        }

        public void setSpanNum(int spanNum) {
            this.spanNum = spanNum;
        }

        public double getSpanMileage() {
            return spanMileage;
        }

        public void setSpanMileage(double spanMileage) {
            this.spanMileage = spanMileage;
        }

        public double getSpanAddOilNum() {
            return spanAddOilNum;
        }

        public void setSpanAddOilNum(double spanAddOilNum) {
            this.spanAddOilNum = spanAddOilNum;
        }
    }

    private static class OilRecord {
        private double addOilNum;//加油量
        private double totalMileage;//总公里
        private double oilConsumption;//油耗

        private boolean isJumpGun;//是否跳枪
        private boolean isOilLampWarning;//是否灯亮
        private boolean isForgetLastTime;//是否忘记上次

        private int id;

        public OilRecord(int id, double addOilNum, double totalMileage, double oilConsumption, boolean isJumpGun, boolean isOilLampWarning, boolean isForgetLastTime) {
            this.addOilNum = addOilNum;
            this.totalMileage = totalMileage;
            this.oilConsumption = oilConsumption;
            this.isJumpGun = isJumpGun;
            this.isOilLampWarning = isOilLampWarning;
            this.isForgetLastTime = isForgetLastTime;
            this.id = id;
        }

        public double getAddOilNum() {
            return addOilNum;
        }

        public void setAddOilNum(double addOilNum) {
            this.addOilNum = addOilNum;
        }

        public double getTotalMileage() {
            return totalMileage;
        }

        public void setTotalMileage(double totalMileage) {
            this.totalMileage = totalMileage;
        }

//        public double getOilConsumption() {
//            return oilConsumption;
//        }
//
//        public void setOilConsumption(double oilConsumption) {
//            this.oilConsumption = oilConsumption;
//        }

        public boolean isJumpGun() {
            return isJumpGun;
        }

        public void setJumpGun(boolean jumpGun) {
            isJumpGun = jumpGun;
        }

        public boolean isOilLampWarning() {
            return isOilLampWarning;
        }

        public void setOilLampWarning(boolean oilLampWarning) {
            isOilLampWarning = oilLampWarning;
        }

        public boolean isForgetLastTime() {
            return isForgetLastTime;
        }

        public void setForgetLastTime(boolean forgetLastTime) {
            isForgetLastTime = forgetLastTime;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }
    }


}

结果对比:

小熊油耗

车有料

最新油耗

7.9升/百公里

最新油耗

7.88升/百公里

平均油耗

7.43升/百公里

平均油耗

7.66升/百公里

 

 

研究记录:

平均油耗:

平均油耗=所有单次油耗的平均值

每公里油费计算方法:

如果能计算出当次油耗,则能计算出当次每公里油费,公式为:
两点间加满,实付金额之和(不含第一个点记录的金额)/两点间的里程差。

两点间油灯亮,实付金额之和(不含当前记录的金额)/两点间的里程差。

历史每公里油费=所有当次每公里油费的均值。

注:另一个小熊油耗计算方式:当前行程每公里油费= 油耗(L/100KM) * 上次加油单价(元/L) / 100

场景算法:

理想状态下的油耗计算:(数值最精准)

描述:每次记账时,都存在跳枪,或都存在灯亮,这样任意两点之间都可以计算油耗,否则就会采用半理想状态下的算法。

算法1:两次跳枪

油耗 = 第二次加油量/这两次记录之间的行驶里程

算法2:两次亮灯

油耗 = 第一次加油量/这两次记录之间的行驶里程

注意:算法1和算法2同时满足,优先选择算法1

半理想状态下的油耗计算:(数值较精准)

描述:从有跳枪,或者灯亮的点开始,直到下一次跳枪或灯亮(中间可以存在多次加油,但不满足计算),算这之间的总加油/总里程。

算法3:两点跳枪

阶段油耗 = 上一次加满(不含)到下一次加满(含)之间加油总量/上一次加满到下一次加满之间的里程

算法4:两点亮灯

阶段油耗 = 上一次油灯亮(含)到下一次油灯亮(不含)之间加油总量/上一次油灯亮到下一次油灯亮之间的里程。

注意:算法3和算法4同时满足,优先采用时间跨度小的算法。

小结:

1、油耗的计算严重依赖于两次计算的跳枪或灯亮,可计算的两点(可以存在多次加油)必需满足都跳枪,或者都灯亮。

2、无法计算油耗说明:暂时无法计算油耗,需要加油加满两次,才能算出一次油耗,或者等油耗警告灯一亮就去加油,加两次后也能算出一次油耗。3、上次没记录,则当次油耗不能计算

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值