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

图片说明

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

5个回答

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

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

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

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

FastLight
FastLight 回复caozhy: 不过我没找到怎么加悬赏分(尴尬)
一年多之前 回复
caozhy
贵阳老马马善福专业维修游泳池堵漏防水工程 回复FastLight: 看我更新的回答。如果问题解决,请采纳,谢谢
一年多之前 回复
FastLight
FastLight php
一年多之前 回复
a22222222q
a22222222q 支持这个回答
一年多之前 回复
showbo
支付宝加好友偷能量挖,胡杨等着我的招呼 正解。可以采纳了,有问题继续在评论里面留言,caozhy会帮你解决的~
一年多之前 回复
caozhy
贵阳老马马善福专业维修游泳池堵漏防水工程 回复DRACULAX05: ???
一年多之前 回复
caozhy
贵阳老马马善福专业维修游泳池堵漏防水工程 回复FastLight: 看我更新的回答
一年多之前 回复
FastLight
FastLight 怎么样能在sql读取的时候就把原始二进制位(或者16进制)读出来?
一年多之前 回复

用Python很简单啊,捂脸

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

(9223379502689557271L,)

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

devmiao
见了你女王大人喵姐还不跪下 回复FastLight: 关注有什么用,姐姐写了半天你又没采纳
一年多之前 回复
FastLight
FastLight 真的是小姐姐吗?先关注再说!
一年多之前 回复

你用的是什么语言?是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

图片说明

首先,
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
devmiao
见了你女王大人喵姐还不跪下 你这个代码太复杂了,不容易理解,看姐姐的回答
一年多之前 回复
caozhy
贵阳老马马善福专业维修游泳池堵漏防水工程 你说“如果溢出,则插入一个最接近该值的浮点数,”这就不对,什么叫最接近该值的浮点数?难道 -3.68861248304756e-311接近9223379502689557271???正确的解释看我的回答吧
一年多之前 回复
caozhy
贵阳老马马善福专业维修游泳池堵漏防水工程 之前没有仔细看,仔细看了下,你的回答根本就错的,还抄袭你,先纠正下你的错误吧
一年多之前 回复
caozhy
贵阳老马马善福专业维修游泳池堵漏防水工程 你看你这事办的不行啊,说人家抄袭你的,起码先要偷偷把回答搞得一模一样。下次碰瓷前先练练吧。
一年多之前 回复

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

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

zhengyajun_email
Yajun-Z 回复: 然后再排除下是否和你读取后的打印终端或是处理代码有关,比如变量声明位数不够啊或终端限制啥的,可能性还是很多的,不一定就是数据库的锅
一年多之前 回复
zhengyajun_email
Yajun-Z 回复FastLight: 我建议检查下插入时是什么类型的,sqlite本身就是动态类型的,也许超过了位数本身就不是按照整型存的
一年多之前 回复
FastLight
FastLight 数据库不是我的,我不能改。里面400多万行数据呢
一年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问