[讨论]如何能稳定的生成 带正负号的四则运算? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
lygmqkl
V2EX    程序员

[讨论]如何能稳定的生成 带正负号的四则运算?

  •  1
     
  •   lygmqkl 2015-10-30 09:12:55 +08:00 3190 次点击
    这是一个创建于 3646 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在做一个有意思的东西,里面有一块是生成四则运算给小朋友学习用的,基本已经都实现了,但是四则运算中有一部分算法我不是很满意,下面举例,希望能找到好的方向,谢谢各位参与。

    要求:
    A. 加减乘除 4 则运算,带正负号
    B. 要能预先控制结果, 比如 A+B=C, 要求 100 以内,先 C = rand(1,100), A = rand(0, C), 这样就能算出 B 了

    说明:
    在简单模式下自然没有什么问题,我遇到的问题是在 A+(-B)*C/(-D+A), 在这种模式下只能大概控制结果的范围,无法做到精确控制

    最新思路:
    我准备下面考虑用填充法来做生成逻辑 比如
    甲 A + B * C / D
    乙 A*B + C/D
    随机选择一个然后用数字去填充位置,貌似也不是很好

    16 条回复    2015-10-30 18:55:53 +08:00
    lygmqkl
        1
    lygmqkl  
    OP
       2015-10-30 09:13:13 +08:00
    希望能分享到合适的思路。
    bearice
        2
    bearice  
       2015-10-30 09:29:05 +08:00   1
    1 )随机生成一个自然数数作为运算结果
    2 )随机生成一个运算符
    3 )随机生成一个自然数作为运算符左参数,计算右参数
    4 )对每个参数重复此过程,直到得到需要的算式长度为止
    lygmqkl
        3
    lygmqkl  
    OP
       2015-10-30 09:30:21 +08:00
    @bearice 目前我是这样做的,但是 除法不好解决
    bearice
        4
    bearice  
       2015-10-30 09:37:10 +08:00
    除法生成参数的时候就在 [1,9] 之间选择然后乘以结果
    lygmqkl
        5
    lygmqkl  
    OP
       2015-10-30 09:39:28 +08:00
    @bearice 这样哦,好像明白你的意思了, that's a good idea.
    lygmqkl
        6
    lygmqkl  
    OP
       2015-10-30 09:40:46 +08:00
    @bearice 顺便问下 乘法 怎么保证结果的准确? 应该是用除法来解决对吧
    demo
        7
    demo  
       2015-10-30 09:42:54 +08:00
    算法这个东西还是需要一定的知识基础的
    icedx
        8
    icedx  
       2015-10-30 09:48:25 +08:00 via Android
    随便生成 然后用 eval 验证结果 只有四则运算的话
    lygmqkl
        9
    lygmqkl  
    OP
       2015-10-30 10:00:51 +08:00
    @demo 其实我是觉得一个数一个数的 loop 太普通了,想看看有没有更好的方法。
    shiye515
        10
    shiye515  
       2015-10-30 10:13:09 +08:00
    首先,我假设楼主的意思是 参与运算的每个值 以及 每步运算的结果 都是不超过 100 的。那么,
    只有一步的算式很好解决,如楼主举的加法的例子,
    两步的运算就是把两个一步的算式嵌套下,(嵌套的意思是把参与运算的算式的一个值替换成一个算式)
    同理 三步的算式就是 一个两步算式嵌套一个一步的算式。
    Karblue
        11
    Karblue  
       2015-10-30 13:58:44 +08:00 via Android
    以前做过出题小程序。就随机生成。然后算一遍把期望的结果组留下就行了
    fengyqf
        12
    fengyqf  
       2015-10-30 15:51:25 +08:00
    随机生成吧,不过在成生后先计算一个结果,是不是在 100 以内,如果不是,就再生成一次。多让机器计算个四则,增加的时间消耗可以忽略
    rogerchen
        13
    rogerchen  
       2015-10-30 16:01:43 +08:00
    楼主这个问题和二十四点差不多,可以选定一个固定的算式 pattern ,枚举求解给定答案的所有算式。
    举个例子,比如说
    A op1 B op2 C op3 D op4 E = F
    其中 F 给定, ABCDE 和 op1~op4 都可以在给定范围内遍历。

    说实在的,这个方法虽然暴力,但是对处理小学生问题还手到擒来的,枚举几亿种可能对现代计算机不过洒洒水了。而且伸缩性也好,如果要缩减 operand 的数量,直接规定为*1 即可。所以楼主随便找个有 eval 算式的工具包,两分钟就搞定。
    dnartz
        14
    dnartz  
       2015-10-30 16:10:44 +08:00
    可以考虑这样一个函数,返回一个以非叶子节点为运算符,叶子节点为数字(含正负号)的语法抽象树。
    tree F(int c, int nOptr) ->
    operator = +-*/ 随机生成一个
    int a, b;
    tree left, right;

    a = rand(1,c);
    switch operator
    b 为算符的右操作数,我们在这个 switch 里根据 operator 反推出 a

    // 如果我们满足继续拆分一个数字的条件,就继续拆分这个数字
    // 拆分的条件就要依楼主的需求而确定了
    // 比如只生成 n 个数字,那么我们可以引入一个参数 int nOptr
    // 我们用随机函数将 int nOptr 划分为 nOptr1 和 nOptr2
    // 表示以 operator 为根节点的语法树左右两侧可以拥有的算符的数目,如果 nOptr1 或者 nOptr2 为 0 ,那就不拆分对应的数字
    // 显然地,一个含有 n 个数字的算式,最多只可能有 n-1 个四则运算符(不是括号)
    // 所以对于一个含有 n 个数字,最后运算结果为 c 的算式,我们应该这样调用 F : F(c, n-1)
    nOptr1 = rand(1, nOptr)
    nOptr2 = nOptr - nOptr1
    if nOptr1 > 0
    left = f(a, nOptr1)
    else
    left = new leafNode(a)
    if nOptr2 > 0
    right = f(b ,nOptr2)
    else
    right = new leafNode(b)

    在生成语法树之后,我们也就可以生成算式了

    在执行完这个算法之后,我们就可以通过这个语法树生成一个算式了
    dnartz
        15
    dnartz  
       2015-10-30 16:12:56 +08:00
    akira
        16
    akira  
       2015-10-30 18:55:53 +08:00
    温习一遍波兰表达式,应该就足够了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2649 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 14:54 PVG 22:54 LAX 07:54 JFK 10:54
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86