Dubbo serialization problem (1) floating point number problem

Dubbo is a distributed service framework, which is commonly used in China. During the development process, a floating point number deserialization problem was encountered.

Problem description, when the parameter is 3.7 of type float, the deserialization gets a value of type double: 3.700000047683716.

Then, I wrote a test program:

 

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;


import com.alibaba.com.cauchess.hessian.io.Hessian2Input;
import com.alibaba.com.caucho.hessian.io.Hessian2Output;


public class TestHessionLite {


	public static void main(String[] args) throws IOException {
		HashMap<String,Float> map=new HashMap<String,Float>();
		Float loat=new Float(3.7);
		map.put("3.7", loat);
		
		byte[] aa=TestHessionLite.serialize(map);
		Object mm=TestHessionLite.deserialize(aa);
		System.out.println(mm.toString());
		
	}
	
	public static byte[] serialize(Object obj) throws IOException{  
		 ByteArrayOutputStream os = new ByteArrayOutputStream();
		 Hessian2Output ho = new Hessian2Output(os);  
		 byte[] cc = null;
		try {
			if(obj==null) throw new NullPointerException();  
		    ho.writeObject(obj);
		    ho.flushBuffer();
		    cc=os.toByteArray();  
		} catch (Exception e) {
			e.printStackTrace ();
		}finally{
			ho.close();
		}
		return cc;  
	    
	}
	
	public static Object deserialize(byte[] by) throws IOException{
		try {
			if(by==null) throw new NullPointerException();  
			ByteArrayInputStream is = new ByteArrayInputStream(by);
		    Hessian2Input hi = new Hessian2Input(is);  
		    return hi.readObject();  
		} catch (Exception e) {
			e.printStackTrace ();
		}
		return null;
	    
	}  
}

 

 

The output is

 

{3.7=3.700000047683716}

 

 

Then test by using 3.5, 3.6 respectively

 

{3.6=3.5999999046325684}
{3.5=3.5}

 

 

After testing, not all decimals have problems, and some decimals will have serialization problems.

My dubbo service serialization uses dubbo's default hession2, and uses the hessian2 protocol, which is the serialization of the transmission object, which is a binary RPC protocol.

After analysis, the problem should be the conversion of decimal floating point numbers to binary.

Later, I checked the relevant information, and wrote a test program for converting between decimal and binary, and found that regardless of decimals, it cannot be represented in float single precision. The specific reasons can be found in the following information http://blog.csdn.net/zcczcw/article/details/7362473.

 

If you change float to double, there will be no precision problem just now, because double is double precision and can save 64-bit binary;

But when the decimal point exceeds 8 digits, the double is also truncated.

 

However, using kryo for serialization will not cause the above problems, because kryo is not stored in binary, but stored in byte arrays, which ensures that the data does not need to be converted.

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;

import org.apache.commons.codec.binary.Base64;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.serializers.JavaSerializer;

public class TestKryo {

	public static void main(String[] args) {

		HashMap<String,Float> map=new HashMap<String,Float>();
		Float loat=new Float(3.7);
		map.put("value", loat);
		
		String aa=TestKryo.serialize(map);
		Object mm=TestKryo.deserialize(aa,HashMap.class);
		System.out.println(mm.toString());
	}
	private static <T extends Serializable> String serialize(T obj) {
        Kryo kryo = new Kryo ();
        kryo.setReferences (false);
        kryo.register(obj.getClass(), new JavaSerializer());
 
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        Output output = new Output(baos);
        kryo.writeClassAndObject(output, obj);
        output.flush();
        output.close();
 
        byte[] b = baos.toByteArray();
        try {
            baos.flush();
            baos.close();
        } catch (IOException e) {
            e.printStackTrace ();
        }
 
        return new String(new Base64().encode(b));
    }
 
    @SuppressWarnings("unchecked")
    private static <T extends Serializable> T deserialize(String obj,
            Class<T> clazz) {
        Kryo kryo = new Kryo ();
        kryo.setReferences (false);
        kryo.register(clazz, new JavaSerializer());
 
        ByteArrayInputStream bais = new ByteArrayInputStream(
                new Base64().decode(obj));
        Input input = new Input(bais);
        return (T) kryo.readClassAndObject(input);
    }
}

 

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=327106112&siteId=291194637