Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG]JSON序列化,BigDecimal值不对。 #1831

Closed
zhao-qiwei opened this issue Sep 5, 2023 · 6 comments
Closed

[BUG]JSON序列化,BigDecimal值不对。 #1831

zhao-qiwei opened this issue Sep 5, 2023 · 6 comments
Labels
bug Something isn't working fixed
Milestone

Comments

@zhao-qiwei
Copy link

zhao-qiwei commented Sep 5, 2023

问题描述

JSON序列化,BigDecimal值不对。
new BigDecimal("1.09600000")序列化JSON的值变成了:1.9600000

环境信息

FastJson2版本:2.0.40
JDK版本:1.8
系统:linux与window都可以再现

重现步骤

测试代码如下:

package net.qmgf.ctrm.api.test;

import java.io.Serializable;
import java.math.BigDecimal;

import com.alibaba.fastjson2.JSONObject;

public class TestJson {

    public static class TestCls implements Serializable {
        private static final long serialVersionUID = 1L;
        private BigDecimal goodsWeight;

        public BigDecimal getGoodsWeight() {
            return goodsWeight;
        }

        public void setGoodsWeight(BigDecimal goodsWeight) {
            this.goodsWeight = goodsWeight;
        }
    }

    public static void main(String[] args) {
        TestCls bean = new TestCls();
        bean.setGoodsWeight(new BigDecimal("1.09600000"));
        System.out.println(JSONObject.toJSONString(bean));
    }
}

输出的结果是:{"goodsWeight":1.9600000}

"1.09600000"变成了:1.9600000

另外,一个建议:BigDecimal转换成String时,默认是否可以这样转换:
BigDecimal dec = new BigDecimal("1.09600000");
String str = dec.stripTrailingZeros().toPlainString();

@zhao-qiwei zhao-qiwei added the bug Something isn't working label Sep 5, 2023
@wenshao wenshao added this to the 2.0.41 milestone Sep 5, 2023
GabrielHwang added a commit to GabrielHwang/fastjson2 that referenced this issue Sep 5, 2023
@zhao-qiwei
Copy link
Author

感觉像是这个方法的问题:com.alibaba.fastjson2.util.IOUtils.writeDecimal

IOUtils.writeDecimal如果修改成这样,可以解决上面的问题,而且效率会更高:

    public static int writeDecimal(byte[] buf, int off, long unscaledVal, int scale) {
        if (unscaledVal < 0) {
            buf[off++] = '-';
            unscaledVal = -unscaledVal;
        }
        if (scale > 0) {
            boolean s = false;
            // 整数部分
            for (int i = POWER_TEN.length - 1; i >= 0; i--) {
                if (i == scale - 2) {
                    break;
                }
                byte c = '0';
                while (unscaledVal >= POWER_TEN[i]) {
                    unscaledVal -= POWER_TEN[i];
                    c++;
                }
                if (c > '0') {
                    s = true;
                }
                if (s) {
                    buf[off++] = c;
                }
            }
            if (!s) {
                buf[off++] = '0';
            }
            // 小数部分
            if (unscaledVal > 0) {
                buf[off++] = '.';
                for (int i = scale - 2; i >= 0; i--) {
                    if (unscaledVal == 0) {
                        break;
                    }
                    byte c = '0';
                    while (unscaledVal >= POWER_TEN[i]) {
                        unscaledVal -= POWER_TEN[i];
                        c++;
                    }
                    buf[off++] = c;
                }
                if (unscaledVal > 0) {
                    buf[off++] = (byte) ('0' + unscaledVal);
                }
            }
        } else {
            boolean s = false;
            for (int i = POWER_TEN.length - 1; i >= 0; i--) {
                byte c = '0';
                while (unscaledVal >= POWER_TEN[i]) {
                    unscaledVal -= POWER_TEN[i];
                    c++;
                }
                if (c > '0') {
                    s = true;
                }
                if (s) {
                    buf[off++] = c;
                }
            }
            buf[off++] = (byte) ('0' + unscaledVal);
            for (int i = scale; i < 0; i++) {
                buf[off++] = '0';
            }
        }
        return off;
    }

    // @formatter:off 
    static final long[] POWER_TEN = {
            10,
            100,
            1000,
            10000,
            100000,
            1000000,
            10000000,
            100000000,
            1000000000,
            10000000000L,
            100000000000L,
            1000000000000L,
            10000000000000L,
            100000000000000L,
            1000000000000000L,
            10000000000000000L,
            100000000000000000L,
            1000000000000000000L,
    };
    // @formatter:off 

@wenshao
Copy link
Member

wenshao commented Sep 5, 2023

@wenshao
Copy link
Member

wenshao commented Sep 5, 2023

感觉像是这个方法的问题:com.alibaba.fastjson2.util.IOUtils.writeDecimal

IOUtils.writeDecimal如果修改成这样,可以解决上面的问题,而且效率会更高:

    public static int writeDecimal(byte[] buf, int off, long unscaledVal, int scale) {
        if (unscaledVal < 0) {
            buf[off++] = '-';
            unscaledVal = -unscaledVal;
        }
        if (scale > 0) {
            boolean s = false;
            // 整数部分
            for (int i = POWER_TEN.length - 1; i >= 0; i--) {
                if (i == scale - 2) {
                    break;
                }
                byte c = '0';
                while (unscaledVal >= POWER_TEN[i]) {
                    unscaledVal -= POWER_TEN[i];
                    c++;
                }
                if (c > '0') {
                    s = true;
                }
                if (s) {
                    buf[off++] = c;
                }
            }
            if (!s) {
                buf[off++] = '0';
            }
            // 小数部分
            if (unscaledVal > 0) {
                buf[off++] = '.';
                for (int i = scale - 2; i >= 0; i--) {
                    if (unscaledVal == 0) {
                        break;
                    }
                    byte c = '0';
                    while (unscaledVal >= POWER_TEN[i]) {
                        unscaledVal -= POWER_TEN[i];
                        c++;
                    }
                    buf[off++] = c;
                }
                if (unscaledVal > 0) {
                    buf[off++] = (byte) ('0' + unscaledVal);
                }
            }
        } else {
            boolean s = false;
            for (int i = POWER_TEN.length - 1; i >= 0; i--) {
                byte c = '0';
                while (unscaledVal >= POWER_TEN[i]) {
                    unscaledVal -= POWER_TEN[i];
                    c++;
                }
                if (c > '0') {
                    s = true;
                }
                if (s) {
                    buf[off++] = c;
                }
            }
            buf[off++] = (byte) ('0' + unscaledVal);
            for (int i = scale; i < 0; i++) {
                buf[off++] = '0';
            }
        }
        return off;
    }

    // @formatter:off 
    static final long[] POWER_TEN = {
            10,
            100,
            1000,
            10000,
            100000,
            1000000,
            10000000,
            100000000,
            1000000000,
            10000000000L,
            100000000000L,
            1000000000000L,
            10000000000000L,
            100000000000000L,
            1000000000000000L,
            10000000000000000L,
            100000000000000000L,
            1000000000000000000L,
    };
    // @formatter:off 

有benchmark数据么?

@wenshao wenshao added the fixed label Sep 5, 2023
@zhao-qiwei
Copy link
Author

没有,
不过这个用的是减法,原来的用的是除法。
通常减法要比除法效率高。

@zhao-qiwei
Copy link
Author

2.0.41-SNAPSHOT版本中已解决。

@wenshao
Copy link
Member

wenshao commented Oct 6, 2023

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working fixed
Projects
None yet
Development

No branches or pull requests

2 participants