喜好

喜好检索

生活 蔬菜

蔬菜大全

思考

见闻与录

BT技术

BT蓝牙技术

标签

Rust基础 2022年10月20日

    简介

    Rust基础

    Rust 圣经

    基础类型

    基础类型

    整数类型

    浮点类型

    浮点类型特殊存储格式导致的 0.1+0.2 != 0.3 的问题( 存储格式导致精度的问题)

    fn get_var_type<T>( _ : &T   ) -> &str {    
     std::any::type_name::<T>()
    }
    
    
    fn main() {
    
        let abc: (f32, f32, f32) = (0.1, 0.2, 0.3);
        let xyz: (f64, f64, f64) = (0.1, 0.2, 0.3);
    
        println!("abc【{}】 {:?}",get_var_type(&abc),abc);                    //  {:?} 打印详细集合元素
        println!("abc.0={}   十进制打印    bit={} ",abc.0,abc.0.to_bits());
        println!("abc.0={}   十六进制打印  bit={:x} ",abc.0,abc.0.to_bits());  // {:x} 打印 16进制  输出显示
        
        println!("abc.0={}   bit={:x}",abc.0,abc.0.to_bits());
        println!("abc.1={}   bit={:x}",abc.1,abc.1.to_bits());
        println!("abc.2={}   bit={:x}",abc.2,abc.2.to_bits());
    //  println!("abc.3={}   bit={}",abc.3,abc.3.to_bits());      // 编译不过 这样就避免了其他语言的运行时错误 no field `3` on type `(f32, f32, f32)`  
        println!("     0.1 + 0.2: {:x}", (abc.0 + abc.1).to_bits());
        println!("           0.3: {:x}", (abc.2).to_bits());
        println!();
    
    
        println!("xyz【{}】 {:?}",get_var_type(&xyz),xyz);
        println!("xyz.0={}   十进制打印    bit={}",xyz.0,xyz.0.to_bits());
        println!("xyz.0={}   十六进制打印  bit={:x}",xyz.0,xyz.0.to_bits());  // {:x} 打印 16进制  输出显示
    
        println!("xyz.0={}   bit={:x}",xyz.0,xyz.0.to_bits());
        println!("xyz.1={}   bit={:x}",xyz.1,xyz.1.to_bits());
        println!("xyz.2={}   bit={:x}",xyz.2,xyz.2.to_bits());
        println!("     0.1 + 0.2: {:x} 【这里是4结尾】", (xyz.0 + xyz.1).to_bits());         // {:x} 打印 16进制  输出显示
        println!("           0.3: {:x} 【这里是3结尾】", (xyz.2).to_bits());
        println!();
    
        let f32_bool_flag = (abc.0 + abc.1 == abc.2);
        println!("abc.0 + abc.1 == abc.2 ----> f32_bool_flag【{}】  tip:精度低导致f32相加字节层面相同(浮点数字节存储格式导致)",f32_bool_flag);
        let f64_bool_flag = (xyz.0 + xyz.1 == xyz.2);
        println!("xyz.0 + xyz.1 == xyz.2 ----> f64_bool_flag【{}】 tip:精度低导致f64相加字节层面不相同(浮点数字节存储格式导致)",f64_bool_flag);
        
        println!();
        println!("int 打印 二进制格式");
        let ijk: (i32, i32, i32) = (30, 60, 90);
    //  println!("ijk.0={}   bit={:x}",ijk.0,ijk.0.to_bits());    //  报错: i32 没有对应的 to_bits() 方法  只有浮点类型有这个方法
        println!("ijk【{}】 {:?}",get_var_type(&ijk),ijk);                    //  {:?} 打印详细集合元素
        println!("ijk.0={}   二进制打印  bit= {:b} ",ijk.0,ijk.0);  // {:b} 打印 2进制  输出显示 显示
        println!("ijk.0={}   八进制打印 ijk.0={:o}  ",ijk.0,ijk.0);  // {:o} 打印 8进制  输出显示
        println!("ijk.0={}   十进制打印 ijk.0={}  ",ijk.0,ijk.0);          // {} 十进制打印
        println!("ijk.0={}   十六进制打印  ijk.0=={:x}  ",ijk.0,ijk.0);    // {:x} 打印 16进制  输出
                
      
        println!("ijk.0={}   bit={:b}",ijk.0,ijk.0);
        println!("ijk.1={}   bit={:b}",ijk.1,ijk.1);
        println!("ijk.2={}   bit={:b}",ijk.2,ijk.2);
        println!("     0.1 + 0.2: {:x}", (ijk.0 + ijk.1));
        println!("           0.3: {:x}", (ijk.2));
        println!();
    }
    
    
    /*输出结果:
    
    
    abc【(f32, f32, f32)】 (0.1, 0.2, 0.3)
    abc.0=0.1   十进制打印    bit=1036831949
    abc.0=0.1   十六进制打印  bit=3dcccccd
    abc.0=0.1   bit=3dcccccd
    abc.1=0.2   bit=3e4ccccd
    abc.2=0.3   bit=3e99999a
         0.1 + 0.2: 3e99999a
               0.3: 3e99999a
    
    xyz【(f64, f64, f64)】 (0.1, 0.2, 0.3)
    xyz.0=0.1   十进制打印    bit=4591870180066957722
    xyz.0=0.1   十六进制打印  bit=3fb999999999999a
    xyz.0=0.1   bit=3fb999999999999a
    xyz.1=0.2   bit=3fc999999999999a
    xyz.2=0.3   bit=3fd3333333333333
         0.1 + 0.2: 3fd3333333333334 【这里是4结尾】
               0.3: 3fd3333333333333 【这里是3结尾】
    
    abc.0 + abc.1 == abc.2 ----> f32_bool_flag【true】  tip:精度低导致f32相加字节层面相同(浮点数字节存储格式导致)
    xyz.0 + xyz.1 == xyz.2 ----> f64_bool_flag【false】 tip:精度低导致f64相加字节层面不相同(浮点数字节存储格式导致)
    
    int 打印 二进制格式
    ijk【(i32, i32, i32)】 (30, 60, 90)
    ijk.0=30   二进制打印  bit= 11110
    ijk.0=30   八进制打印 ijk.0=36
    ijk.0=30   十进制打印 ijk.0=30
    ijk.0=30   十六进制打印  ijk.0==1e
    ijk.0=30   bit=11110
    ijk.1=60   bit=111100
    ijk.2=90   bit=1011010
         0.1 + 0.2: 5a
               0.3: 5a
    
    仔细看,对 f32 类型做加法时,0.1 + 0.2 的结果是 3e99999a,0.3 也是 3e99999a,
    因此 f32 下的 0.1 + 0.2 == 0.3 通过测试,但是到了 f64 类型时,结果就不一样了,
    因为 f64 精度高很多,因此在小数点非常后面发生了一点微小的变化,0.1 + 0.2 以 4 结尾,
    但是 0.3 以3结尾,这个细微区别导致 f64 下的测试失败了,并且抛出了异常。
    */
    
    
    
    

    NaN类型

    fn get_var_type<T>( _ : &T   ) -> &str {    
     std::any::type_name::<T>()
    }
    
    
    fn main() {
          let x = (-42.0_f64).sqrt();          // f32  f64  浮点类型 才有的方法 sqrt()
    	  let y = (42.0_f64).sqrt(); 
       // let z = (-42_i32).sqrt();          // i32  i64  整数类型 没有求 sqrt() 平方根的方法 报错   method sqrt not found in `i32`
          println!("x_type[{}]  x={}",get_var_type(&x), x);
    	  println!("y_type[{}]  y={}",get_var_type(&y), y);
    	  
    	  //  i32  i64  整数类型  判断 is_nan() 非意义的方法  报错   method is_nan not found in `i32`
    	  // let a_int: i32  = 10;
    	  // if a_int.is_nan() {    println!("a_int 是 nan 意味着 未定义的数学行为") }
    	
    	  if x.is_nan() {   
            println!("x 是 float 浮点类型的 nan 意味着 未定义的数学行为")
          }
    	  
    }
    
    
    /* 
    x_type[f64]  x=NaN
    y_type[f64]  y=6.48074069840786
    x 是 float 浮点类型的 nan 意味着 未定义的数学行为
    */