python 解决 eval 函数 计算 关于浮点数误差问题

项目一

首先 eval本身转化的是二进制的数据,转化过程中再转换回来肯定带有小数位,那直接使用eval对表达式进行计算,但是由于eval是将表达式中的数值使用浮点型进行计算,会由于精度的问题产生误差。

例如eval(‘8.51*13.5’)=114.88499999999999,四舍五入保留两位小数之后,结果为:114.88,会产生0.01的误差

所以为了解决这个问题, 再本项目中 我写了一个方法可以提供转化,需要提供两个参数的值,一个是提供需要计算的公式:公式不限制长度 ,第二个是需要提供一个字典。

from decimal import Decimal


def add_decimal(args):
    return f"Decimal('{args}')"


def add(dict_data:dict, formula):
    dic = {}
    for i in dict_data.keys():
        if i in formula:
            y = add_decimal(str(dict_data[i]))
            dic[i] = y
    print(dic)
    mula = []
    for i in formula:
        if i.strip():
            mula.append(i)
    print(mula)
    text = ''
    for i in mula:
        if i in dic.keys():
            i = dic[i]
            text += i
        else:
            text += i
    # print(text,"=",eval(text))
    return eval(text)


if __name__ == '__main__':
    formula = 'A * B + C'
    dict = {'A': '8.51', 'B': '13.5', 'C':'1000'}
    print(add(dict,formula))  # 运行结果 1114.885

觉得有用点赞加关注吧 写代码不容易!

项目二

写了一个关于公式断言和字符串断言的方法,返回结果是[预期结果,实际结果,True/False]
成功为True ,失败为False

import json
from decimal import Decimal


def add_decimal(args):
    return f"Decimal('{args}')"


def add(dict_data:dict, formula):
    dic = {}
    for i in dict_data.keys():
        if i in formula:
            y = add_decimal(str(dict_data[i]))
            dic[i] = y
    mula = []
    for i in formula:
        if i.strip():
            mula.append(i)
    text = ''
    for i in mula:
        if i in dic.keys():
            i = dic[i]
            text += i
        else:
            text += i
    return eval(text)


def str_split(formula:str,expect:str):
    formula = formula.split(',')
    expect = expect.split(',')
    return formula,expect


def compare_fixvalue(dic:dict, expect:str):
    """  字符串断言
    dic = {'E': 'lll', 'SDSD abc': 'ABC', 'F': 'ooo', "Venue": "HV", "Total": "1,000.00", "ACP8": "","AA":"1"}
    expect =  '{"Venue":"HV","Total":"1,000.00","ACP8":"","AA":"2"}'
    status = compare_fixvalue(dic, expect)
    预期结果,实际结果 返回值
    [['HV', 'HV', True], ['1,000.00', '1,000.00', True], ['', '', True], ['2', '1', False]]
    """
    status_list = []
    dict_expect = json.loads(expect)
    for i in dict_expect.keys():
        if dict_expect[i] in dic.values():
            if dict_expect[i] in dic[i]:
                result_list = [dict_expect[i], dic[i], True]
                status_list.append(result_list)
                # print(f'预期结果 value:{dict_expect[i]}, 实际结果 value:{dic[i]}, True')
            else:
                result_list = [dict_expect[i], dic[i], False]
                status_list.append(result_list)
                # print(f'预期结果 value:{dict_expect[i]}, 实际结果 value:{dic[i]}, False')
        else:
            if i not in dic.keys():
                result_list = [i, 'None key', False]
                status_list.append(result_list)
                # print(f'预期结果 key:{i}, 实际结果找不到对应 key, False')
            else:
                result_list = [dict_expect[i], dic[i], False]
                status_list.append(result_list)
                # print(f'预期结果 value:{dict_expect[i]}, 实际结果 value:{dic[i]}, False')
    return status_list


def spare_compare_fixvalue(dic:dict, formula:str, expect:str):
    """  备用 字符串断言
    dic = {'E':'lll','SDSD abc':'ABC','F':'ooo'}
    formula = 'E,SDSD abc,F'
    expect = 'lll,ABC,oo'
    status = spare_compare_fixvalue(dic, formula, expect)
    print(status)
    比较值相等 返回 True 否则 False
    """
    status_list = []
    formula, expect = str_split(formula,expect)
    if len(formula) != len(expect):
        raise Exception("预期结果与实际结果条数不一致")
    else:
        for i in range(len(formula)):
            status = analyze_fixvalue(dic,formula[i],expect[i])
            status_list.append(status)

        status_value = [str(j) for j in status_list]
        # status_value = "" + join(status_value)
        return status_value


def analyze_fixvalue(dic:dict, formula, expect):
    """ dic :字典数据 ,formula :实际结果str ,expect:预期结果str"""
    formula, expect = formula.strip(), expect.strip()
    if str(formula).isalpha() is True or formula.isspace() is False:
        formula = dic[formula] # print('实际结果',formula) # print('预期结果',expect)
        try:
            if formula == expect:
                print(f'expect: {expect}, actual: {formula}, return:',True)
                return True
            else:
                print(f'expect: {expect} != actual: {formula} return:',False)
                return False
        except Exception as e:
            print(f'raise Exception 异常 --> {e}')
            return False
    else:
        raise Exception("预期结果不仅仅包含字母或字符串带中间空格,请调用 compare_fumula 方法")


def compare_fumula(dic:dict, formula:str, expect:str):
    """ 公式断言
    dic = {'A': '2', 'B': '3', 'C': '5', 'D': '5'}
    # 公式断言
    # formula = 'A + B, B + C,B + C'
    # expect = 'A + B, B + C,B + C'
    ## status = compare_fumula(dic, formula,'5.4')  # 输入实际值
    # status = compare_fumula(dic, formula, expect)  # 输入字典 value
    预期结果,实际结果 返回值
    [['A + B', 'A + B', True], [' B + C', ' B + C', True], ['B + C', 'B + C', True]]
    """
    status_list = []
    formula, expect = str_split(formula,expect)
    if len(formula) != len(expect):
        raise Exception("预期结果与实际结果条数不一致")
    else:
        for i in range(len(formula)):
            status = analyze_formula(dic,formula[i],expect[i])
            value = [expect[i],formula[i],status]
            status_list.append(value)
        return status_list


def analyze_formula(dic:dict, formula, expect, deviation=0.0):
    """ dic :PDF字典数据 ,formula :计算公式 ,expect:预期结果 ,deviation 可控制范围 """
    formula, expect = formula.strip(), expect.strip()
    expect_value = None
    if expect in '+' or '-' or '*' or '/':
        expect_value = add(dic, str(expect))
        # print("预期结果 :",expect_value)
    else:
        expect = dic[expect] if str(expect).isalpha() is True else expect
        expect = eval(expect)
    expect = expect_value if expect_value is not None else expect
    actual = add(dic, formula)
    # print("实际结果 :",actual)
    try:
        assert float(deviation) == abs(actual - expect)
        # print(f'expect:{expect}, actual:{actual}, Controllable range:{deviation}')
        return True
    except AssertionError as error:
        # print(f'raise AssertionError 异常 --> expect:{expect},actual:{actual} ', error.__str__())
        return False


if __name__ == '__main__':
    # 公式断言
    dic = {'A': '1232.012', 'B': '1252.018', 'C': '5', 'D': '5'}
    formula = 'B * A, D + B, B + C' # 计算公式
    expect = 'A * B, D + B, A + B'  # 预期结果:写入公式、数字、都可,与计算公式个数对应
    status = compare_fumula(dic, formula, expect)  # 输入字典 value
    print(status)  
    # [['A * B', 'B * A', True], [' D + B', ' D + B', True], [' A + B', ' B + C', False]]
    
	# 字符串断言
    dic = {'E': 'lll', 'SDSD abc': 'ABC', 'F': 'ooo', "Venue": "HV", "Total": "1,000.00", "ACP8": "","AA":"1","RACE1_WIN_POOL STATUS":"DEFINED","RACE15_WIN_POOL STATUS":"DEFINED"}
    expect = '{"RACE1_WIN_POOL STATUS": "DEFINED", "RACE15_WIN_POOL STATUS": "D/EFINEDZ"}'
    status = compare_fixvalue(dic, expect)
    print(status)  # [['DEFINED', 'DEFINED', True], ['D/EFINEDZ', 'DEFINED', False]]