FastLight
FastLight
采纳率100%
2019-04-15 16:52 阅读 725

sqlite 中使用无符号整数存储的数据,再读取的时候,“溢出”的数据全变成浮点数了,怎么解决?

1000

图片说明

谁能用php帮我解决掉这个问题,加分。

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

5条回答 默认 最新

  • 已采纳
    caozhy 从今以后生命中的每一秒都属于我爱的人 2019-04-15 17:06

    看你希望怎么解决,因为我们不知道你的约束条件在那里。但是可以做很多办法来补偿。

    比如说在数据库层面,用两个整数字段,或者字符串字段来存储单个的整数。
    比如说,数据库不能修改,但是可以通过编程语言做修正。

    需要你先给出你的场景,还有代码,然后才好找到进一步的方法

    C/C++直接用指针暴力转换就可以了。

    不同的编译器对64bit的整数的支持不一样,以下代码在gcc编译
    在线验证网址:https://c.runoob.com/compile/12

    #include <stdio.h>
    
    int main()
    {
        double d = -6.29187711124658e-311;
        __int64_t *l = (__int64_t *)&d;
        printf("%llu", *l);
        return 0;
    }
    

    9223384771755824298

    关键是Java,它不支持指针,所以没办法简单暴力,需要用BigInteger
    代码如下:

    import java.math.BigInteger;
    
    public class HelloWorld {
        public static void main(String []args) {
            double d = -6.29187711124658e-311;
            long value = Double.doubleToRawLongBits(d);
            BigInteger bi = new BigInteger("0");
            BigInteger base = new BigInteger("1");
            Boolean sign = (value < 0);
            if (value < 0)
            {
                value += 9223372036854775807L;
                value += 1L;
            }
            while (value > 0)
            {
                bi = bi.add(new BigInteger(String.valueOf(value % 2)).multiply(base));
                base = base.multiply(new BigInteger("2"));
                value /= 2;
            }
            if (sign) bi = bi.add(new BigInteger("9223372036854775808"));
            System.out.println(bi);
        }
    }
    

    9223384771755824298

    如果一种语言不支持 Double.doubleToRawLongBits 这样的方法
    那么你可以根据IEEE标准的浮点数的格式自己去转换。

    如果你还需要别的语言的例子,可以继续追问。
    如果问题解决,麻烦采纳下,谢谢

    下面是SQLite数据类型参考手册上关于这个问题的解释:

    datatype reference in SQLite
    INTEGER. The value is a signed integer, stored in 1, 2, 3, 4, 6, or 8 bytes depending on the magnitude of the value.
    That is, you can only store values from -2**63 to (2**63-1). What does SQLite do for a value outside of this range? As we saw earlier, it switches over into floating point. Again, quoting from the SQLite reference:
    REAL. The value is a floating point value, stored as an 8-byte IEEE floating point number.
    Many programmers are familiar with this type under the name double.

    PHP版本

    <?php
    $binarydata = pack("d", -3.68861248304756e-311);
    $value = unpack("Q", $binarydata);
    echo("float format: ");
    echo($value[1] + pow(2, 64));
    echo("\ninteger format: ");
    $ofvalue = $value[1] + 9223372036854775808;
    echo (" 92233");
    echo ($ofvalue + 72036854775808);
    ?>
    

    float format: 9.2233795026896E+18
    integer format: 9223379502689557504

    点赞 4 评论 复制链接分享
  • devmiao devmiao 2019-04-16 09:54

    用Python很简单啊,捂脸

    import struct
    d = -3.68861248304756e-311
    arr = struct.pack('d', d)
    l = struct.unpack('Q', arr)
    print(l)
    
    

    (9223379502689557271L,)

    姐姐的回答最简单,采纳姐姐一下下吧

    点赞 3 评论 复制链接分享
  • dabocaiqq dabocaiqq 2019-04-16 10:04

    你用的是什么语言?是Virtual BASIC么?看看下面的是不是适合你

    Public Class Form1
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim d As Double = Double.Parse(TextBox1.Text)
            Dim bytes() = BitConverter.GetBytes(d)
            Dim l As ULong = BitConverter.ToUInt64(bytes, 0)
            Label1.Text = l
        End Sub
    End Class
    
    

    图片说明

    点赞 1 评论 复制链接分享
  • zhengyajun_email Yajun-Z 2019-04-15 17:10

    既然你都说了是溢出了,那说明的的数据长度已经超过了声明长度了嘛,那写进去的数据本身就没意义了,你读出来还怎么能还原?

    要么你增加数据类型的长度,要么就换种类型,比如用TEXT类型,读取的时候转成整数就行了

    点赞 评论 复制链接分享
  • DRACULAX05 DRACULAX05 2019-04-15 20:11

    首先,
    sqlite这个数据库和一般的mysql那些数据库不同
    如果是mysql,那么你根本没办法插入一个溢出的整数
    而sqlite却可以,它的处理方式是:
    如果溢出,则插入一个最接近该值的浮点数
    所以这里你是幸运的,数据库的值并没有因为溢出而被破坏,而是保留了其正确的二进制值,只不过是以浮点数的方式
    这也是为什么你去取值的时候肯定会返回一个浮点数

    那么问题就变成了,如何把这个取出的浮点数还原为其原来的数字

    我不知道你用的什么语言,这里我用C++做一个示例给你:

    #include "pch.h"
    #include <stdio.h>
    #include <iostream>
    #include <math.h>
    
    using namespace std;
    
    int main(void)
    {
        __int64 nMax = pow(2, 63);
    
        double d = -3.68861248304756e-311;
        __int64 nOverflow = *((__int64*)&d);
    
        printf("max=%llu\n", nMax);
        printf("overflow=%llu\n", nOverflow);
        printf("delta=%llu\n", nOverflow-nMax);
        return 0;
    }
    

    d就是你从数据库取出的值,这里我用了你图片第一个溢出值做示例
    nMax是64位有符号整数的最大正值,超出这个就会溢出
    nOverflow就是从d转换过来的整数值

    其核心思想就是把读取到的浮点数,存到内存中,然后以整数的方式读取同样一块内存

    输出如下:

    max=9223372036854775808
    overflow=9223379502689557271
    delta=7465834781463
    
    点赞 评论 复制链接分享

相关推荐