当前位置: 首页 > 知识库问答 >
问题:

这是如何打印“你好世界”的?

岳嘉容
2023-03-14

我发现了这个怪事:

for (long l = 4946144450195624l; l > 0; l >>= 5)
    System.out.print((char) (((l & 31 | 64) % 95) + 32));

输出:

hello world

这是怎么工作的?

共有3个答案

郭凯
2023-03-14

有意思!

可见的标准ASCII字符范围为32到127。

这就是为什么你会看到32和95(127-32)。

实际上每个字符都被映射到5位(你可以找到每个字符的5位组合),然后所有的位被级联形成一个大数。

正长是63位的数字,大到足以容纳12个字符的加密形式。因此它足够大,可以容纳hello word,但是对于较大的文本,您应该使用较大的数字,甚至是biginteger。

在一个应用程序中,我们希望通过SMS传输可见的英文字符、波斯语字符和符号。如您所见,有32(波斯语字符数)+95(英文字符和标准可见符号数)=127可能的值,可以用7位表示。

我们将每个UTF-8(16位)字符转换为7位,获得了56%以上的压缩比。这样我们就可以在相同数量的sms中发送两倍长度的文本。(不知怎的,这里也发生了同样的事情)。

廉元龙
2023-03-14

为上述答案增加了一些价值。下面的groovy脚本打印中间值。

String getBits(long l) {
return Long.toBinaryString(l).padLeft(8,'0');
}

for (long l = 4946144450195624l; l > 0; l >>= 5){
    println ''
    print String.valueOf(l).toString().padLeft(16,'0')
    print '|'+ getBits((l & 31 ))
    print '|'+ getBits(((l & 31 | 64)))
    print '|'+ getBits(((l & 31 | 64)  % 95))
    print '|'+ getBits(((l & 31 | 64)  % 95 + 32))

    print '|';
    System.out.print((char) (((l & 31 | 64) % 95) + 32));
}

在这儿

4946144450195624|00001000|01001000|01001000|01101000|h
0154567014068613|00000101|01000101|01000101|01100101|e
0004830219189644|00001100|01001100|01001100|01101100|l
0000150944349676|00001100|01001100|01001100|01101100|l
0000004717010927|00001111|01001111|01001111|01101111|o
0000000147406591|00011111|01011111|00000000|00100000| 
0000000004606455|00010111|01010111|01010111|01110111|w
0000000000143951|00001111|01001111|01001111|01101111|o
0000000000004498|00010010|01010010|01010010|01110010|r
0000000000000140|00001100|01001100|01001100|01101100|l
0000000000000004|00000100|01000100|01000100|01100100|d
邓欣德
2023-03-14

4946144450195624符合64位,其二进制表示为:

 10001100100100111110111111110111101100011000010101000

该程序从右到左对每一个5位组解码一个字符

 00100|01100|10010|01111|10111|11111|01111|01100|01100|00101|01000
   d  |  l  |  r  |  o  |  w  |     |  o  |  l  |  l  |  e  |  h

对于5位,可以表示2=32个字符。英文字母表包含26个字母,这就为32-26=6个符号留下了空间。有了这个编码方案,你可以有所有26个(一个案例)英文字母和6个符号(空格在其中)。

for循环中的>>=5从一个组跳到另一个组,然后5位组被隔离,并且在句子L&31中使用掩码31=11111的数字

现在,代码将5位值映射到相应的7位ascii字符。这是比较棘手的部分,请检查下表中小写字母的二进制表示形式:

  ascii   |     ascii     |    ascii     |    algorithm
character | decimal value | binary value | 5-bit codification 
--------------------------------------------------------------
  space   |       32      |   0100000    |      11111
    a     |       97      |   1100001    |      00001
    b     |       98      |   1100010    |      00010
    c     |       99      |   1100011    |      00011
    d     |      100      |   1100100    |      00100
    e     |      101      |   1100101    |      00101
    f     |      102      |   1100110    |      00110
    g     |      103      |   1100111    |      00111
    h     |      104      |   1101000    |      01000
    i     |      105      |   1101001    |      01001
    j     |      106      |   1101010    |      01010
    k     |      107      |   1101011    |      01011
    l     |      108      |   1101100    |      01100
    m     |      109      |   1101101    |      01101
    n     |      110      |   1101110    |      01110
    o     |      111      |   1101111    |      01111
    p     |      112      |   1110000    |      10000
    q     |      113      |   1110001    |      10001
    r     |      114      |   1110010    |      10010
    s     |      115      |   1110011    |      10011
    t     |      116      |   1110100    |      10100
    u     |      117      |   1110101    |      10101
    v     |      118      |   1110110    |      10110
    w     |      119      |   1110111    |      10111
    x     |      120      |   1111000    |      11000
    y     |      121      |   1111001    |      11001
    z     |      122      |   1111010    |      11010

在这里,您可以看到我们想要映射的ascii字符以第7位和第6位开始(11xxxxx)(space除外,它只有第6位开启),您可以使用96(96=11000002014)对5位编码进行,这应该足以进行映射,但对于space(该死的space!)

现在我们知道,必须特别注意处理空间的同时,其他字符。为此,该代码将提取的5位组的第7位(但不是第6位)打开,并使用OR 6464=1000000220(L&31 64)。

到目前为止,5位组的形式为:10xxxxx*(空格为1011111*=95)。如果我们可以将空间映射到0而不影响其他值,那么我们可以打开第6位,这应该是全部。下面是mod 95部分的作用,空格是1011111,使用mod操作(l&31 64)%95)只有空格返回到0,在此之后,代码通过将32=10000042添加到前一个结果((l&31 64)%95)+32)将5位值转换为有效的ascii字符来打开第6位

isolates 5 bits --+          +---- takes 'space' (and only 'space') back to 0
                  |          |
                  v          v
               (l & 31 | 64) % 95) + 32
                       ^           ^ 
       turns the       |           |
      7th bit on ------+           +--- turns the 6th bit on

下面的代码html" target="_blank">执行相反的过程,给定一个小写字符串(最多12个字符),返回可以与操作的代码一起使用的64位长的值:

public class D {
    public static void main(String... args) {
        String v = "hello test";
        int len = Math.min(12, v.length());
        long res = 0L;
        for (int i = 0; i < len; i++) {
            long c = (long) v.charAt(i) & 31;
            res |= ((((31 - c) / 31) * 31) | c) << 5 * i;
        }
        System.out.println(res);
    }
}    
 类似资料:
  • 最近我一直在使用带有大量数字的循环来打印: 我知道这是一种非常愚蠢的方法,但我还从未在Java中使用过任何计时器库。如何修改上述内容,使其每3秒打印一次?

  • 下面是我在网上找到的一些代码: 此代码将打印到屏幕上;你可以看到它在这里运行。我可以清楚地看到写的,但它是反向的。这段代码是如何工作的?这是如何编译的呢? 编辑:我在IntellIJ中尝试了这段代码,它工作得很好。但是,由于某些原因,它在notepad++和cmd中不起作用。我还没有找到解决方法,所以如果有人找到了,请在下面评论。

  • 本文向大家介绍TypeScript 你好,世界,包括了TypeScript 你好,世界的使用技巧和注意事项,需要的朋友参考一下 示例 这里我们有一个类 Greeter,它有一个构造函数和一个 greet 方法。我们可以使用 new 关键字构造一个类的实例,然后传入一个字符串,我们希望 greet 方法输出到控制台。Greeter 类的实例存储在 Greeter 变量中,然后我们调用 greet 方

  • 本文向大家介绍qml 你好,世界,包括了qml 你好,世界的使用技巧和注意事项,需要的朋友参考一下 示例 一个简单的应用程序在窗口中心显示文本“ Hello World”。            

  • 本文向大家介绍xaml 你好,世界,包括了xaml 你好,世界的使用技巧和注意事项,需要的朋友参考一下 示例 这是WPF中XAML页面的简单示例。它由XAML中最常见的元素a Grid,aTextBlock和aButton组成。 语法 描述 <Window> 根容器,用于承载可视化数据并使用户能够与之交互的内容。WPF窗口是XAML(.xaml)文件(其中元素为根)和CodeBehind(.cs)

  • 本文向大家介绍processing 你好,世界,包括了processing 你好,世界的使用技巧和注意事项,需要的朋友参考一下 示例 编写处理代码的最简单方法是简单地调用一系列函数。在处理编辑器中按运行按钮,处理将运行您的代码。这是一个例子: 此代码创建一个200x200窗口,绘制一个蓝色背景,将填充颜色更改为绿色,然后在屏幕中间绘制一个圆圈。 但是,大多数处理草图将使用预定义的setup()和d