Category: algorithm

  • float_and_double

    浮点数是指用符号,尾数,基数和指数这四部分来表示的小数。因为计算机内部使用的是二进制数,所以基数自然是2。

    来源

    CPU中的二进制数据(小数篇)

    计算机浮点数规格化表示

    单精度与双精度是什么意思,有什么区别?

    浮点数

    • 双进度 64 位,8byte

    • 单精度 32 位,4byte

    浮点数构成`

    浮点数构成_双精度

    浮点数构成_单精度

    1. IEEE 754標準規定:非正規形式的浮點數的指數偏移值比正規形式的浮點數的指數偏移值小1。例如,最小的正規形式的單精度浮點數的指數部分編碼值為1,指數的實際值為-126;而非規約的單精度浮點數的指數域編碼值為0,對應的指數實際值也是-126而不是-127。實際上非正規形式的浮點數仍然是有效可以使用的,只是它們的絕對值已經小於所有的規約浮點數的絕對值;即所有的非規約浮點數比規約浮點數更接近0。規約浮點數的尾數大於等於1且小於2,而非規約浮點數的尾數小於1且大於0

    2. 小数部分是原十进制数值变为二进制后再经过规格化,规格化后省去唯一的整数1之后剩下的0.0100000 00000000 00000000写进去的。

    3. 指数部分是由指数实际值-3再加上固定值(这里取IEEE754标准的固定值2**(e-1)-1,e为储存指数的比特长度,在这里是8 bit)(单精度时指数偏移度为127,目的是为了同时可以表示正和负的指数,即00000000-11111111分别对应-127 — 128)。

      # 十进制运算
      0.15625-(1.0/8)-0-(1.0/32) = 0
      # 因式分解,用二的倍数表示
      0.15625=(1.0/8)+0+(1.0/32)
      # 转为二进制
      0.15625=(1)*(0+0.00101)=(1)*(1+0.01)x2^(-3)
      # 二进制下小数位为0.01
      # 尾数为0100 0000 0000 0000 0000 000
      # 指数 -3
      (-3)-(-127)=134 => 0b0111_1100
      
      

    一个32位单精度浮点数-3.75表示的例子:

    #首先转化为2进制表示
    −3.75=−(2+1+1/2+1/4)=−1.111×2^1
    #整理符号位并进行规格化表示
    −1.111×21=(−1)(1)×(1+0.1110 0000 0000 0000 0000 000)×2^1
    # 尾数为1110 0000 0000 0000 0000 000
    # 指数为1-127=128=0b10000000
    

    精度

    浮点数的尾数是二进制的,转化之后,有一些数无法表示,这也是精度丢失的原因.

  • 使用位运算进行取模

    一般取模 $A mod B$

    12%8=4

    如果 $B = 2^n$ 以使用 $&(B-1)$ 代替 $%B$ 来取模.

    12&(8 -1) = 4
    12&(2^3 – 1) = 4

    glibc strlen 就用到了

    #include <string.h>
    #include <stdlib.h>
    
    #undef strlen
    
    #ifndef STRLEN
    # define STRLEN strlen
    #endif
    
    /* Return the length of the null-terminated string STR.  Scan for
       the null terminator quickly by testing four bytes at a time.  */
    size_t
    STRLEN (const char *str)
    {
      const char *char_ptr;
      const unsigned long int *longword_ptr;
      unsigned long int longword, himagic, lomagic;
    
        /*利用取模运算,控制这里最大为 str + 8*/
      /* Handle the first few characters by reading one character at a time.
         Do this until CHAR_PTR is aligned on a longword boundary.  */
      for (char_ptr = str; ((unsigned long int) char_ptr
                & (sizeof (longword) - 1)) != 0;
           ++char_ptr)
        if (*char_ptr == '\0')
          return char_ptr - str;
    
      /* All these elucidatory comments refer to 4-byte longwords,
         but the theory applies equally well to 8-byte longwords.  */
    
      longword_ptr = (unsigned long int *) char_ptr;
    
      /* Bits 31, 24, 16, and 8 of this number are zero.  Call these bits
         the "holes."  Note that there is a hole just to the left of
         each byte, with an extra at the end:
         bits:  01111110 11111110 11111110 11111111
         bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD
         The 1-bits make sure that carries propagate to the next 0-bit.
         The 0-bits provide holes for carries to fall into.  */
      himagic = 0x80808080L;
      lomagic = 0x01010101L;
      if (sizeof (longword) > 4)
        {
          /* 64-bit version of the magic.  */
          /* Do the shift in two steps to avoid a warning if long has 32 bits.  */
          himagic = ((himagic << 16) << 16) | himagic;
          lomagic = ((lomagic << 16) << 16) | lomagic;
        }
      if (sizeof (longword) > 8)
        abort ();
    
        /*代替一次比较一个character,每次读取多个 byte,然后一起比较,提高了读取的效率。就是批处理的思想*/
      /* Instead of the traditional loop which tests each character,
         we will test a longword at a time.  The tricky part is testing
         if *any of the four* bytes in the longword in question are zero.  */
      for (;;)
        {
          longword = *longword_ptr++;
    
          if (((longword - lomagic) & ~longword & himagic) != 0)
        {
          /* Which of the bytes was the zero?  If none of them were, it was
             a misfire; continue the search.  */
    
          const char *cp = (const char *) (longword_ptr - 1);
    
          if (cp[0] == 0)
            return cp - str;
          if (cp[1] == 0)
            return cp - str + 1;
          if (cp[2] == 0)
            return cp - str + 2;
          if (cp[3] == 0)
            return cp - str + 3;
          if (sizeof (longword) > 4)
            {
              if (cp[4] == 0)
            return cp - str + 4;
              if (cp[5] == 0)
            return cp - str + 5;
              if (cp[6] == 0)
            return cp - str + 6;
              if (cp[7] == 0)
            return cp - str + 7;
            }
        }
        }
    }
    libc_hidden_builtin_def (strlen)
    
  • 常见的坐标系

    左手坐标系

    左手坐标系

    右手坐标系

    右手坐标系

    左手法则 与 右手法则

    左手法则与右手法则

  • Base64

    Base64

    所谓Base64,就是说选出64个字符—-小写字母a-z、大写字母A-Z、数字0-9、符号”+”、”/”(再加上作为垫字的”=”,实际上是65个字符)—-作为一个基本字符集。然后,其他所有符号都转换成这个字符集中的字符。
    Base64将三个字节转化成四个字节,因此Base64编码后的文本,会比原文本大出三分之一左右。

    Base64 Table

    Index Char Index Char Index Char Index Char
    0 A 16 Q 32 g 48 w
    1 B 17 R 33 h 49 x
    2 C 18 S 34 i 50 y
    3 D 19 T 35 j 51 z
    4 E 20 U 36 k 52 0
    5 F 21 V 37 l 53 1
    6 G 22 W 38 m 54 2
    7 H 23 X 39 n 55 3
    8 I 24 Y 40 o 56 4
    9 J 25 Z 41 p 57 5
    10 K 26 a 42 q 58 6
    11 L 27 b 43 r 59 7
    12 M 28 c 44 s 60 8
    13 N 29 d 45 t 61 9
    14 O 30 e 46 u 62 +
    15 P 31 f 47 v 63 /

    (more…)