我想构建一个供私人使用的数学评估器(在进行评估时没有安全限制),它可以为我提供数学陈述的可能结果。假设这里的 random() 指的是 range() 并且内置的 python range 不适用于浮点值。因此,虽然它应该默认执行正常的评估,但返回值应该位于列表或集合中。 所以,它应该评估基础数学。
"3" -> [3]
"round(419.9)" -> [420]
"round(3.14, 1)" -> [3.1]
它还应该列出所有可能结果的评估。
"[1,2,3]" -> [1,2,3]
它还应该递归地评估多个列表
"[2,1] - 1" -> [1,0]
"[2,1] - [0,1]" -> [2, 1, 0] (with internal evalulation being combination of two list recursive evaulation of expression "[2,1] - 0" and "[2,1] - 1")
"[2,1] * [1,2]" -> [4,2,1]
然后只需将随机函数编码为范围并返回列表,然后评估应该给出答案。
"random(3)" -> [0, 1, 2]
"random(3,4)" -> [3]
"round(random(0.1, 0.5), 1)" -> [0.1, 0.2, 0.3, 0.4]
最后,它还应该具有来自 stdlib 数学模块的变量和函数,例如
"log(e)" -> [1] # math.log(math.e)
"tau/pi" -> [2.0] # math.tau/math.pi
虽然这个测试用例超出了讨论范围,但如果可以编写这样的代码,那就太酷了。我确实看到一些评估者很好地处理了这段代码,而当我尝试使用 sympy、ast.eval 和正常 eval 时,出现了重大错误。
"2(3)" -> [6]
"2(3(3))" -> [18]
我设法编写了通过一些测试用例的代码,但很难使其全部正确。
import random
def evaluate_expression(expression):
# Define safe functions and constants to use within eval
def custom_function(expression, roundval=0):
if isinstance(expression, list):
return [round(item, roundval) for item in expression]
else:
return round(expression, roundval)
safe_dict = {
'random': lambda *args: list(range(int(args[0]), int(args[1]) + 1)),
'round': custom_function,
}
# Add some common mathematical constants
safe_dict.update({
'pi': 3.141592653589793,
'e': 2.718281828459045
})
# Try to evaluate the expression
try:
result = eval(expression, {"__builtins__": None}, safe_dict)
# If the result is a single number, return it in a list
if isinstance(result, (int, float)):
return [result]
# If the result is a list, return it as is
elif isinstance(result, list):
return result
else:
raise ValueError("Unsupported result type")
except (SyntaxError, NameError, TypeError, ValueError) as e:
return str(e)
这些是测试用例
# Test cases
assert evaluate_expression("3") == [3]
assert evaluate_expression("round(419.9)") == [420]
assert evaluate_expression("round(3.14, 1)") == [3.1]
assert evaluate_expression("[1,2,3]") == [1,2,3]
assert evaluate_expression("[2,1] - 1") == [1,0]
assert evaluate_expression("[2,1] - [0,1]") == [2, 1, 0]
assert evaluate_expression("[2,1] * [1,2]") == [4,2,1]
assert evaluate_expression("random(3)") == [0,1,2]
assert evaluate_expression("random(3, 4)") == [3]
assert evaluate_expression("round(random(0.1, 0.5), 1)") == [0.1, 0.2, 0.3, 0.4]
assert evaluate_expression("log(e)") == [1]
assert evaluate_expression("tau/pi") == [2.0]
#out of scope
assert evaluate_expression("2(3)") == [6]
assert evaluate_expression("2(3(3))") == [18]
我认为如果这个测试用例通过,像“random(1,9) * random(1,9)”这样的东西不应该出错并且应该产生“[1,2,3,4,5,6,7, 8]*[1,2,3,4,5,6,7,8]" 然后评估应该生成一个大列表。作为旁注,我还设法生成了一个自定义随机范围生成器。 (当输入是(0.01,0.05)时,我不太关心列表中的0.5,但如果可以改进这个功能,那就太酷了)
def custom_random(start, end):
ten = 10**len(str(start).split('.')[-1])
if isinstance(start, int):
mul = 1
elif isinstance(start, float):
if len(str(start)) == 3:
mul = 0.1
elif len(str(start)) == 4:
mul = 0.01
if isinstance(start, int) and isinstance(end, int):
return list(range(start, end))
elif isinstance(start, float) and isinstance(end, float):
return [round(i * mul, len(str(start).split('.')[1])) for i in range(int(start * ten), int(end * ten) + 1)]
else:
raise TypeError("Unsupported input type")
print(custom_random(1, 5))
print(custom_random(3, 4))
print(custom_random(10, 50))
print(custom_random(0.1, 0.5)) #prints also 0.5 but it should not print 0.5, but only upto 0.4? but not big of bug anyways
print(custom_random(0.01, 0.05)) #prints also 0.05 but it should not print 0.05, but only upto 0.4? but not big of bug anyways
print(custom_random(0.05, 0.09))
以下是
custom_random
函数的更简洁版本:
def custom_random(start, end):
def round_to_precision(number, precision):
return round(number * 10 ** precision) / 10 ** precision
step = 1 if isinstance(start, int) else 10 ** -len(str(start).split('.')[-1])
if isinstance(start, (int, float)) and isinstance(end, (int, float)):
result = [round_to_precision(i, len(str(start).split('.')[-1])) for i in
range(int(start * 10 ** len(str(start).split('.')[-1])), int(end * 10 ** len(str(start).split('.')[-1])) + 1)]
if result[-1] > end:
result.pop()
return result
else:
raise TypeError("Unsupported input type")
此版本保留了
custom_random
函数的功能,同时使用辅助函数 round_to_precision
来实现更清晰的代码。