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

2023-06-11 17:40:10 +08:00
 ellermister

要求:

例题

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

2717 次点击
所在节点    程序员
18 条回复
fengjianxinghun
2023-06-11 18:04:01 +08:00
eval("1+2")
ellermister
2023-06-11 18:05:35 +08:00
@fengjianxinghun 不算,这个太变态了
Mohanson
2023-06-11 18:17:58 +08:00
先实现半加器, 再使用半加器实现全加器, 这样你就实现了加法.

有了加法就有了减法.

有了加法就有了乘法.

有了加, 减, 乘就能实现除法.
2113ic
2023-06-11 19:02:50 +08:00
@ellermister new function('exp', 'return exp')😂
vituralfuture
2023-06-11 19:42:20 +08:00
转补码,用逻辑运算实现一个全加器,然后级联做成 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
2023-06-11 19:45:34 +08:00
@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
2023-06-11 19:51:58 +08:00
你就直接问 GPT ,如何使用 AND OR XOR NOT 四个操作符实现加减乘除不就完了……
是人干的事么……
话说经常有直播网站加载 wasm ,为了实现高于目标机器位数的乘除法(估计用于签名或加解密),可以略微参考一下,也不能算是完全没有用处。
javak
2023-06-11 20:25:28 +08:00
这个太简单了,十多年前,我大二的时候,《数据结构与算法设计》这门课,其中一节课的作业而已。
test0x01
2023-06-11 20:41:53 +08:00
利用 AST,很多语言提供现成的解析器,自己再后继处理下。这样算不算?
agagega
2023-06-11 20:43:46 +08:00
你的语言表述很不清晰。究竟是「不用这门语言的四则运算符实现四则运算」还是「用这门语言实现一个四则运算表达式的计算工具」?
maggch97
2023-06-11 21:21:07 +08:00
@agagega 按照这个表述我觉得问的应该就是"如何用栈实现基础四则运算",否则不会有这么拧巴的表述
duke807
2023-06-11 21:30:40 +08:00
没意义,即便你写一个 cpu 仿真代码,仿真 cpu 寄存器,依然会用到 “编程语言提供的基础四则运算”

建议 op 直接学 verilog ,可以帮助理解最最底层的东西
jorneyr
2023-06-11 22:31:09 +08:00
数据结构与算法的基础:逆波兰表达式。
lopssh
2023-06-11 22:36:42 +08:00
很基础啊...逆波兰式+表达式栈求值。
phcbest
2023-06-11 22:48:32 +08:00
```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
2023-06-11 23:45:23 +08:00
阿隆佐·邱奇提出的 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)))`。这是邱奇数的标准表示方式。
crz
2023-06-12 10:27:45 +08:00
LykorisR
2023-06-12 10:51:34 +08:00
大一上计算机系统基础实验课程,和这个一模一样

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/947774

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX