能否用你所熟悉的开发语言,实现基础四则运算? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
ellermister
V2EX    程序员

能否用你所熟悉的开发语言,实现基础四则运算?

  •  
  •   ellermister 2023 年 6 月 11 日 3308 次点击
    这是一个创建于 945 天前的主题,其中的信息可能已经有所发展或是发生改变。

    要求:

    • 不能使用内联汇编 /内嵌其他语言
    • 不能使用网络 API
    • 不能使用编程语言提供的基础四则运算语法或函数

    例题

    • 1+2 = 3
    • 4*8 = 32
    • 7/2 = 3.5 / 3
    • 2-2 = 0

    突然想到,这种有没有好的思路实现啊 ?

    18 条回复    2023-06-12 10:51:34 +08:00
    fengjianxinghun
        1
    fengjianxinghun  
       2023 年 6 月 11 日   1
    eval("1+2")
    ellermister
        2
    ellermister  
    OP
       2023 年 6 月 11 日   1
    @fengjianxinghun 不算,这个太变态了
    Mohanson
        3
    Mohanson  
       2023 年 6 月 11 日
    先实现半加器, 再使用半加器实现全加器, 这样你就实现了加法.

    有了加法就有了减法.

    有了加法就有了乘法.

    有了加, 减, 乘就能实现除法.
    2113ic
        4
    2113ic  
       2023 年 6 月 11 日
    @ellermister new function('exp', 'return exp')
    vituralfuture
        5
    vituralfuture  
       2023 年 6 月 11 日   2
    转补码,用逻辑运算实现一个全加器,然后级联做成 32 位全加器,这样就有了做加减法的能力,乘除法同理,计算出的结果可以转回原码再求出真值

    不过如何实现真值到原码到补码?很简单,利用按位逻辑运算,比如 C++中,一条语句`x=1;`,那么 x 就对应内存中一个存储位置,可以用按位逻辑运算取出每一位,然而非常巧的是,内存中的数值是以补码形式存储的,所以就能够取出补码每一位,也就是说不需要求补码,补码已经躺在内存里了

    我写了一个程序来简单说明,只有循环用到了加法`i++`,但是所有循环的次数都是确定的,也就是说**循环可以展开,替换成循环体重复 32 次,相当于没有使用加法**
    ```
    #include <iostream>

    using namespace std;


    void getComplementCode(bool arr[32], int num) {
    int mask = 1;
    for (int i = 0; i < 32; i++) {
    arr[i] = num & mask;
    num = num >> 1;
    }
    }

    int getTrueValue(const bool arr[32]){
    int s = 0;
    for (int i = 0; i < 32; i++) {
    s = s | (arr[i] << i);
    }
    return s;
    }



    void add1(bool a, bool b, bool &s, bool c0, bool &c1) {
    s = a ^ b ^ c0;
    c1 = (a && b) || ((a ^ b) && c0);
    }

    void add32(bool a[32], bool b[32], bool s[32], bool c = false) {
    bool carray[32];
    add1(a[0], b[0], s[0], c, carray[0]);
    for (int i = 1; i < 32; i++) {
    add1(a[i], b[i], s[i], carray[i-1], carray[i]);
    }
    }

    void getTwoComplement(bool arr[32]){
    for(int i=0;i<32;i++){
    arr[i] = ! arr[i];
    }
    bool temp[32];
    bool one[32];
    one[0] = true;
    for(int i=1;i<32;i++){
    one[i] = false;
    }
    add32(arr, one, temp);
    for(int i=0;i<32;i++){
    arr[i] = temp[i];
    }
    }

    int add(int a, int b){
    bool A[32], B[32], S[32];
    getComplementCode(A, a);
    getComplementCode(B, b);
    add32(A, B, S);
    return getTrueValue(S);
    }

    int sub(int a, int b){
    bool A[32], B[32], S[32];
    getComplementCode(A, a);
    getComplementCode(B, b);
    getTwoComplement(B);
    add32(A, B, S);
    return getTrueValue(S);
    }


    int main() {
    cout << add(10, 5) << endl;
    return 0;
    }
    ```

    乘法的话,32 位加 32 位结果是 64 位的,按照这个方式也能够实现

    我写的了一个测试用例如下
    ```
    BOOST_AUTO_TEST_CASE(addTest1){
    const int times = 10000;
    int a = (int)random();
    int b = (int)random();
    BOOST_TEST(a + b == add(a, b));
    }
    ```
    测试通过


    除法和浮点数运算,计组课上没讲,不知道具体怎么做,不过道理都是相同的,模拟机器运算,把 C++写成 verilog
    vituralfuture
        6
    vituralfuture  
       2023 年 6 月 11 日
    @vituralfuture 测试写错了,修改如下
    ```
    BOOST_AUTO_TEST_CASE(addTest1) {
    const int times = 10000;
    int a, b;
    for (int i = 0; i < times; i++) {
    a = (int) random();
    b = (int) random();
    BOOST_TEST(a + b == add(a, b));
    }
    }
    ```
    结果
    yankebupt
        7
    yankebupt  
       2023 年 6 月 11 日
    你就直接问 GPT ,如何使用 AND OR XOR NOT 四个操作符实现加减乘除不就完了……
    是人干的事么……
    话说经常有直播网站加载 wasm ,为了实现高于目标机器位数的乘除法(估计用于签名或加解密),可以略微参考一下,也不能算是完全没有用处。
    javak
        8
    javak  
       2023 年 6 月 11 日
    这个太简单了,十多年前,我大二的时候,《数据结构与算法设计》这门课,其中一节课的作业而已。
    test0x01
        9
    test0x01  
       2023 年 6 月 11 日 via Android
    利用 AST,很多语言提供现成的解析器,自己再后继处理下。这样算不算?
    agagega
        10
    agagega  
       2023 年 6 月 11 日 via iPhone
    你的语言表述很不清晰。究竟是「不用这门语言的四则运算符实现四则运算」还是「用这门语言实现一个四则运算表达式的计算工具」?
    penzi
        11
    penzi  
       2023 年 6 月 11 日
    @agagega 按照这个表述我觉得问的应该就是"如何用栈实现基础四则运算",否则不会有这么拧巴的表述
    duke807
        12
    duke807  
       2023 年 6 月 11 日 via Android
    没意义,即便你写一个 cpu 仿真代码,仿真 cpu 寄存器,依然会用到 “编程语言提供的基础四则运算”

    建议 op 直接学 verilog ,可以帮助理解最最底层的东西
    jorneyr
        13
    jorneyr  
       2023 年 6 月 11 日
    数据结构与算法的基础:逆波兰表达式。
    lopssh
        14
    lopssh  
       2023 年 6 月 11 日 via Android
    很基础啊...逆波兰式+表达式栈求值。
    phcbest
        15
    phcbest  
       2023 年 6 月 11 日
    ```kotlin
    fun add(a: Int, b: Int): Int {
    var carry: Int
    var sum: Int
    do {
    sum = a xor b
    carry = (a and b) shl 1
    a = sum
    b = carry
    } while (b != 0)
    return a
    }

    fun subtract(a: Int, b: Int): Int {
    return add(a, add(b.inv(), 1))
    }

    fun multiply(a: Int, b: Int): Int {
    var result = 0
    var shift = 0
    var bCopy = b
    while (bCopy != 0) {
    if (bCopy and 1 == 1) {
    result = add(result, a shl shift)
    }
    shift++
    bCopy = bCopy shr 1
    }
    return result
    }

    fun divide(a: Int, b: Int): Int {
    var dividend = a
    var divisor = b
    var quotient = 0
    while (dividend >= divisor) {
    dividend = subtract(dividend, divisor)
    quotient = add(quotient, 1)
    }
    return quotient
    }
    ```
    zktsin
        16
    zktsin  
       2023 年 6 月 11 日 via iPhone   1
    阿隆佐邱奇提出的 lambda 演算是一种形式系统,在它中,所有的函数都只有一个输入。你可以使用它来表示所有可计算的函数。为了用它实现加减乘除四则运算,我们先需要定义一些基础函数。

    以下是用 Javascript ES6 表示的四则运算的 lambda 演算:

    ```Javascript
    const ZERO = f => x => x;
    const OnE= f => x => f(x);
    const TWO = f => x => f(f(x));
    const THREE = f => x => f(f(f(x)));

    const SUCC = n => f => x => f(n(f)(x));
    const PLUS = m => n => f => x => m(f)(n(f)(x));
    const MULT = m => n => f => m(n(f));
    const PRED = n => f => x => n(g => h => h(g(f)))(u => x)(u => u);
    const SUB = m => n => n(PRED)(m);

    const toInteger = n => n(x => x + 1)(0);

    let four = SUCC(THREE);
    console.log(toInteger(four)); // 4

    let three = PRED(four);
    console.log(toInteger(three)); // 3

    let seven = PLUS(three)(four);
    console.log(toInteger(seven)); // 7

    let twelve = MULT(two)(six);
    console.log(toInteger(twelve)); // 12

    let two = SUB(four)(two);
    console.log(toInteger(two)); // 2
    ```

    这段代码首先定义了一些常数,如 `ZERO`、`ONE`、`TWO`、`THREE`。然后,定义了四则运算的函数 `SUCC`、`PLUS`、`MULT`、`PRED` 和 `SUB`。

    其中 `SUCC` 是后继函数,表示加一操作。`PLUS` 是加法函数,它将两个数相加。`MULT` 是乘法函数,它将两个数相乘。`PRED` 是前驱函数,表示减一操作。`SUB` 是减法函数,它将两个数相减。

    注意,所有的这些函数都是通过函数组合和应用来定义的,没有使用任何 Javascript 特有的语法,完全按照邱奇的理论来实现。

    然后,`toInteger` 函数用于将这些邱奇数转换为 Javascript 中的整数,便于我们查看和验证结果。

    最后的部分是一些运算示例,验证了这些函数的正确性。

    注意,以上代码中的所有数都是邱奇数,它们都是以单参数函数的形式表示的。例如,`THREE` 是一个函数,它接受一个函数 `f` 和一个参数 `x`,并返回 `f(f(f(x)))`。这是邱奇数的标准表示方式。
    LykorisR
        18
    LykorisR  
       2023 年 6 月 12 日
    大一上计算机系统基础实验课程,和这个一模一样
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2861 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 14:29 PVG 22:29 LAX 06:29 JFK 09:29
    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