动手动脑

1.源码反码补码和浮点数

原码的表示与机器数真值表示的一样,即用第一位表示符号,其余位表示数值

反码的表示方法为:

正数的反码是其原码本身。

负数的反码是在其原码的基础上,符号位不变,其余各位取反。

补码的表示方法为:

正数的补码是其原码本身。

负数的补码是在其原码的基础上,符号位不变,其余各位取反后加1(即在反码的基础上加1)。

    0      0         0  .   0        0         0

 

2^(2) 2^(1) 2^(0) 2^(-1) 2^(-2) 2^(-3).....

 这就是一个计算机内储存浮点数的方法。计算机只能识别二进制01,而且2^(-1),2^(-2),2^(-3),这些数字都有限制,不可能正在有限的位数内表达正正好好的原本的数字。所以只能退而求其次。去找一个和该数字差不多的数字。

下面则是一个表示0.2的过程

0.01 = 1/4 = 0.25 ,太大

0.001 =1/8 = 0.125 , 又太小

0.0011 = 1/8 + 1/16 = 0.1875 , 逼近0.2了

0.00111 = 1/8 + 1/16 + 1/32 = 0.21875 , 又大了

0.001101 = 1/8+ 1/16 + 1/64 = 0.203125 还是大

0.0011001 = 1/8 + 1/16 + 1/128 = 0.1953125 这结果不错

0.00110011 = 1/8+1/16+1/128+1/256 = 0.19921875
已经很逼近了, 就这样吧。

我们用一个更明显的例子

以0.09f为例

可以这样查看一下一个float的内部表示
Float.floatToRawIntBits(0.09f)

你将会得到:1035489772, 这是10进制的, 转化成二进制, 在前面加几个0补足 32位就是:

0 01111011 01110000101000111101100

你可以看到它分成了3段:
第一段代表了符号(s) : 0 正数, 1 负数 , 其实更准确的表达是 (-1) ^0

第二段是阶码(e):01111011  ,对应的10进制是 123

第三段是尾数(M)

你看到了尾数和阶码,就会明白这其实是所谓的科学计数法:
(-1)^s * M * 2^e

所以,理论上,只要有更多的位数,我们能表达的数字就会越精确。但是现实,内存不是无限的。我们通常没必要为了这些极小的误差而占用过多的内存。所以浮点数4字节,double8字节。这样的已经满足普通人的正常需求了。但是对于像是银行那种,对数字要求极其严格的机构。需要的精准的数字,而不是这种相似的数字。所以就需要使用高精度算法。通俗的讲,就是把数字转化为字符串。然后通过我们所掌握的小数的乘除加减。来人为的进行操作。而不是再依赖于计算机定义的加减乘除。

 

int X=100;

int Y=200;

System.out.println("X+Y="+X+Y);

System.out.println(X+Y+"=X+Y");

对于Java而言,sout里面的+号,既可以表示字符串的拼接,也可以当作算术运算符进行加法操作。如果不加以规定,则会出现二义性。所以就规定,该+号的左右两边的值,如果有一方是String类型,则该加号意为字符串的拼接。如果加号两边都是Number类型,则是算数运算符。

对于这次的课堂测试,测出很多问题。对于一个程序的把握不准。很难通过老师规定的步骤循序渐进。通常都是做完第一点后则全部注释掉。再重新写第二段。这样很麻烦。但也没有什么好的方法。只能在一次一次的写代码中不断的进步。

对于课下作业。实话实说。个人感觉,老师在陪着我们玩游戏。用一些在企业中,已经广为应用的东西的名字,来布置作业。但是其内容和社会上该东西真正的做法完全不一样。就像是这次的课下作业验证码。在我没看老师留下的ppt时,我个人感觉,这个东西是需要服务器才能完成的东西。但是怎么现在就布置下来了?等我看了作业要求后才知道。就是随机生成一个字符串而已。对于字符串。很容易写,即使不依赖Java中自带的某些东西。也可以,像是把可能用到字符都储存下来,再用随机数去拿去下标,进而构成一个验证码。之后为了防止验证码重复,还可以将该验证码加入set容器。而且又因为set的查找,非常快。所以耗时也不多。

posted @ 2022-09-12 00:01  啦啦啦one  阅读(89)  评论(0编辑  收藏  举报