Brainfuck语言实战

本文介绍了一种极简编程语言Brainfuck的基本运算操作,包括加法、减法、乘法及除法的实现方法,并提供了相应的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一,加减乘除

二,逻辑运算

三,SPOJ TEST


一,加减乘除

1,加法

用BF语言做加法,输入a+b,计算a+b=c,并输出c,假设a b c都是一位数(下同)

看了百度百科上的代码:

,>++++++[<-------->-],,[<+>-],<.>.

我最开始写的解释器是用cin接收一个字符,接收不了换行符,所以略改之后变成:

,>++++++[<-------->-],,[<+>-]<.>

运行示例:

后来觉得还是应该能输入换行符才对,这样才是完备的,所以又在末尾补上 ,. 得到

,>++++++[<-------->-],,[<+>-]<.>,.

改了解释器之后,运行:

2,减法

原理和加法一样

,>,,>++++++[<-------->-]<[<->-]<.> 

运行示例:

改了解释器之后,运行,>,,>++++++[<-------->-]<[<->-]<.> ,.

3,乘法

,>,,>++++++++[<------<------>>-]<<
[>[>+>+<<-]>>[<<+>>-]<<<-]
>>>++++++[<++++++++>-]<.,.

4,除法

除法果然比乘法复杂很多很多,暂时不研究这个。

二,逻辑运算

1,整数转化成布尔值

简单版:

,[->[-]+<]>.

可视化版:

,>++++++[-<-------->]<
[->[-]+<]
>>++++++[-<++++++++>]<.

    

2,或

简单版:

,[->>[-]+<<]
>,[->[-]+<]
>.

可视化版:

,>++++++[-<-------->]<
[->>[-]+<<]
>,>>++++++[-<<-------->>]<<
[->[-]+<]
>>++++++[-<++++++++>]<.

      

3,且

简单版:

,>,<
[->[->[-]+<]<]
>>.

可视化版:

,>++++++[-<-------->]
,>++++++[-<-------->]
<<
[->[->[-]+<]<]
>>>++++++[-<++++++++>]<.

     

4,非

简单版:

,>+<
[->[-]<]>.

可视化版:

,>++++++[-<-------->]+<
[->[-]<]>
>++++++[-<++++++++>]<.

   

三,SPOJ TEST

SPOJ的TEST(题库第一题)

Life, the Universe, and Everything

Your program is to use the brute-force approach in order to find the Answer to Life, the Universe, and Everything. More precisely... rewrite small numbers from input to output. Stop processing input after reading in the number 42. All numbers at input are integers of one or two digits.
 

Example

Input:
1
2
88
42
99

Output:
1
2
88

Information

In case of any problems with your code, you can take a look in the forum, you'll find the answer, only for this problem, in various languages.

题意:

输入一串数,依次输出,直到42就停止。

思路一:

用乘法,把每相邻的2个字符都减掉48(0的ASCII码)就得到对应的数字值x和y,计算出x*10+y,再判断是不是42即可。

代码:

,>++++++[-<---- ---->]
>+
[
<,>[-]++++++[-<---- ---->]<<
[->>+++++ +++++>>+<<<<]
>[->+<<+>]
>>++++++[-<---- --->]
<[->[-]+<<+>]
<[->+<]
>>>>++++++[-<++++ ++++>]
<<[->.<]>[-]<<]

我在纸上转述了每一行是做什么的,这一行执行完之后指针停留的位置,以及那些格子有数(其他格子一定是0)

其中第8行的描述里面写的()运算符指的是将整数转化成布尔值,即0变成0,非0变成1

然而提交运行的结果的rouya超时,于是我就肉眼debug + 测试

最后发现‘8’和‘\n’这2个字符的组合会让程序停止。

验证一下,ASCII码分别是56和10,分别减48就是8和-38,按照两位数组合起来就是8 * 10 + (-38) = 42

这也太巧了吧。。。

但是这也不至于导致超时啊,于是我把这个代码翻译成C++提交,果然是Wrong answer

思路二:

分开判断2个数,当相邻两个数分别是4和2的时候才停止

,>>+
[[-]
<,<
[->>+>+<<<]>>>
[-<<<+>>>]<<
[->>+>+<<<]>>>
[-<<<+>>>]<<
---------- ---------- ---------- ---------- ---------- -->
---------- ---------- ---------- ---------- ----------
[->[-]+<]<
[->[-]+<]>
[-<[-]+>]>[-<<[-]+>>]<<
[->+>+<<]>>
[-<<+>>]<
[-<<<.>>>]<<<[-]>
[-<+>]>
]

这次逻辑对了,然而提交的结果依然是超时,不知道为什么。

同样的,我把这个代码翻译成C++提交:

#include <iostream>
using namespace std;

void run()
{
    char arr[1000]={0};
    char *p = arr;
    *p=getchar();
p++;
p++;
*p = *p + 1;
while(*p){while(*p){*p = *p - 1;
};
p--;
*p=getchar();
p--;
while(*p){*p = *p - 1;
p++;
p++;
*p = *p + 1;
p++;
*p = *p + 1;
p--;
p--;
p--;
};
p++;
p++;
p++;
while(*p){*p = *p - 1;
p--;
p--;
p--;
*p = *p + 1;
p++;
p++;
p++;
};
p--;
p--;
while(*p){*p = *p - 1;
p++;
p++;
*p = *p + 1;
p++;
*p = *p + 1;
p--;
p--;
p--;
};
p++;
p++;
p++;
while(*p){*p = *p - 1;
p--;
p--;
p--;
*p = *p + 1;
p++;
p++;
p++;
};
p--;
p--;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
p++;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
*p = *p - 1;
while(*p){*p = *p - 1;
p++;
while(*p){*p = *p - 1;
};
*p = *p + 1;
p--;
};
p--;
while(*p){*p = *p - 1;
p++;
while(*p){*p = *p - 1;
};
*p = *p + 1;
p--;
};
p++;
while(*p){*p = *p - 1;
p--;
while(*p){*p = *p - 1;
};
*p = *p + 1;
p++;
};
p++;
while(*p){*p = *p - 1;
p--;
p--;
while(*p){*p = *p - 1;
};
*p = *p + 1;
p++;
p++;
};
p--;
p--;
while(*p){*p = *p - 1;
p++;
*p = *p + 1;
p++;
*p = *p + 1;
p--;
p--;
};
p++;
p++;
while(*p){*p = *p - 1;
p--;
p--;
*p = *p + 1;
p++;
p++;
};
p--;
while(*p){*p = *p - 1;
p--;
p--;
p--;
cout<<char(*p);
p++;
p++;
p++;
};
p--;
p--;
p--;
while(*p){*p = *p - 1;
};
p++;
while(*p){*p = *p - 1;
p--;
*p = *p + 1;
p++;
};
p++;
};

}

int main()
{
    run();
    return 0;
}

这个程序就通过了!

难道是我自己写的翻译器会忽略BF代码的隐藏BUG,然后我这个程序偏偏就有这个BUG导致超时,但是我翻译出来的C++代码却抹去了这个BUG?

于是我又自己写了个解释器:Brainfuck语言 解释器_csuzhucong的博客-CSDN博客

把我这个代码放进去,运行结果还是好好的,并不会超时啊!

难道我的BF程序、翻译器、解释器都刚好有相配套的BUG?

思路三:

把思路二的逻辑稍微简化了一点:

,>>+
[[-]
<,<
[->>+>+<<<]>>>
[-<<<+>>>]<<
[->>+>+<<<]>>>
[-<<<+>>>]<<
---------- ---------- ---------- ---------- ---------- -->
---------- ---------- ---------- ---------- ---------- <
[->>[-]+<<]>[->[-]+<]>
[-<+<+>>]<
[-<<<.>>>]
<<<[-]>
[-<+>]>
]

居然!又双叒叕超时了,简直快怀疑人生了!

难道我的BF程序(思路二)、BF程序(思路三)、翻译器、解释器都刚好有相配套的BUG?

于是,我又用自己的解释器执行标程:

+[>>----------
[++++++++++<,----------]
>--------------------------------------------------
>----------------------------------------------------
>
[
<++++++++++++++++++++++++++++++++++++++++++++++++++++
<++++++++++++++++++++++++++++++++++++++++++++++++++
[>]<
[.<]++++++++++.---------->
[>]>>
]<
[++++++++++++++++++++++++++++++++++++++++++++++++++++
<++++++++++++++++++++++++++++++++++++++++++++++++++
[>]<
[.<]++++++++++.---------->
[>]>
]<
[>++++++++++++++++++++++++++++++++++++++++++++++++++++
<++++++++++++++++++++++++++++++++++++++++++++++++++
[>]<
[.<]++++++++++.---------->
[>]
]<
]

结果也没啥问题(说明我的档解释器没有明显BUG),但是格式略有差异:

而我的程序是:

到了这一步,无外乎就是四种情况:

(1)输入输出的问题,关于换行或者文件结尾的处理可能有问题

(2)我的BF程序(思路二)、BF程序(思路三)、翻译器、解释器都刚好有相配套的BUG

(3)标程有问题

(4)标程没问题但是OJ的解释器有问题,把我的程序解释错了

接下来,首先测试一下,用文件输入和控制台输入的差异、文件尾有没有换行或空行的差异

本地文件里面放:

测试结果:

我的程序读取控制台或者文件都正常,

   

标程读取文件运行不正常!

这里面涉及到2个差异:

(1)回车和换行符的差异导,控制台上的是回车键‘\13’文件中的是换行符‘\10’

(2)系统的差异,linux上的换行符LF和windows上的换行符CRLF不一样,所以标程在linux上读取文件应该没问题,在windows上读文件因为多了一个'\r'所以不会停止

这个解释和下面的行为是一致的:

   

标程好像很厉害,很严格,输入4242、4243、4342都不会停止,唯独输入42才停止。

虽然最终也没能AC,但是还是准备告一段落了,主要是BF语言没找到很标准的解释器,自己写的也不知道有没有BUG,而且SPOJ本来也不熟,之前从来没碰过,虽然听说很厉害但是说不准还是有问题呢?

不对!等一下!我再挣扎一下!

让我最后再看下matrix67的这个题的代码是怎么写的:

>>,>,
< <<++++++[>>--------<<-]>>---- [>>+>]<[<]> <<++++++[>>++++++++<<-]>>++++
> <<++++++[>>--------<<-]>>-- [>+>]<[<]>> <<++++++[>>++++++++<<-]>>++ >
[<<. [-]>[-<+>],>[-]<<
<<++++++[>>--------<<-]>>---- [>>+>]<[<]> <<++++++[>>++++++++<<-]>>++++
><<++++++[>>--------<<-]>>-- [>+>]<[<]>> <<++++++[>>++++++++<<-]>>++ >]

他在博客里面说,这个代码是AC的,然后我贴到自己的解释器里面执行,确实是对的,而且格式和我的一模一样:

然后我把这个代码提交到SPOJ,居然!居然!!!居然是Runtime error!

漂亮!

后来在浏览维基词条的时候发现一块内容刚好和我想到的这几个问题吻合:

Brainfuck语言 未定义行为_csuzhucong的博客-CSDN博客

然后我又看到了一个可视化的工具:https://fatiherikli.github.io/brainfuck-visualizer/

在这运行了我的代码之后,我发现我忽略了一种最基本的可能,我的程序可能真的太慢了!

Brainfuck,是一种极小化的计算机语言,它是由Urban Müller在1993年创建的。由于fuck在英语中是脏话,这种语言有时被称为brainf*ck或brainf***,甚至被简称为BF。 【内含:BF解释器,BF解释器源码,BF写的几个小程序】 ReadMe: Brainfuck 编程语言 [图灵完全] [8条指令] 语法: > 指针加一 < 指针减一 + 指针指向的字节的值加一 - 指针指向的字节的值减一 . 输出指针指向的单元内容(ASCII码) , 输入内容到指针指向的单元(ASCII码) [ 如果指针指向的单元值为零,向后跳转到对应的]指令的次一指令处 ] 如果指针指向的单元值不为零,向前跳转到对应的[指令的次一指令处 特性: 8KB 环状内存(初始化为0) <>操作不会越界 加减操作环状 +-操作不会溢出(0xFF + 为 0x00) 文件说明: bf.exe 解释器 Usage: bf [-options] source where options include: -b buffered input (default mode) 缓冲输入(按回车才输入,默认) -i not buffered input 无缓冲输入 -e not buffered input without echo 无缓冲输入且不回显 bf.cpp 解释器的源代码(纯C实现) hello.txt HelloWorld程序 up.txt 这个程序将你的输入(小写字母)转换为大写(回车结束) add.txt 这个程序对两个一位数做加法,并输出结果(如果结果也只有一位数的话)(例如:输入2+3) mul.txt 这个程序对两个一位数做乘法,并输出结果(如果结果也只有一位数的话)(例如:输入2*3) factor.txt 这个程序分解多位数的因子,并输出结果(例如:输入1000) numwarp.txt 这个程序输入 ()-./0123456789abcdef 和空格的字符串,显示很有趣的排列结果(例如:输入520 1314) prime.txt 这个程序输入一个多位整数,输出从1到这个整数间的所有素数(例如:输入100) quine.txt 这个程序输出源代码本身 [以上程序,基本上依靠回车确认]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值