10

所以,

问题

我对行乘法有疑问。在 SQL 中,有一个SUM()函数可以为一组行的某些字段计算总和。我想得到乘法,即表

+------+
| 数据 |
+------+
| 2 |
| -1 |
| 3 |
+------+

结果就是2*(-1)*3 = -6这样。我使用DOUBLE数据类型来存储我的数据值。

我的方法

从学校数学可知log(A x B) = log(A) + log(B)- 因此可以用来创建所需的表达式,例如:

SELECT
  IF(COUNT(IF(SIGN(`col`)=0,1,NULL)),0,
    IF(COUNT(IF(SIGN(`col`)<0,1,NULL))%2,-1,1)
    *
    EXP(SUM(LN(ABS(`col`))))) as product
FROM `test`;

- 在这里你看到了这种方法的弱点 - 因为log(X)是未定义的X<=0- 我需要在计算整个表达式之前计算负号。这个 fiddle给出了示例数据和查询。另一个弱点是我们需要找出列值中是否有 0(因为它是一个样本,在实际情况下,我将为具有某些条件的表行的某些子集选择产品 - 即我不能简单地从我的表中删除 0-s,因为结果零产品是某些行子集的有效且预期的结果)

细节

现在,最后,我的问题主要部分是:当我们有这样的表达式时如何处理情况:X*Y*Zand here X < MAXF, Y<MAXF, but X*Y>MAXFand X*Y*Z<MAXF- 所以我们可能有数据类型溢出(这里MAXFMySQL 数据类型的限制)。样品在这里。上面的查询运行良好,但我可以始终确定它会正确处理吗?即当某些子产品导致溢出时,可能还有另一种溢出问题的情况,但整个产品都可以(没有溢出)。

或者可能有另一种方法来查找行产品?此外,在表中可能有数百万条记录(-1.1<X<=1.1主要是,但可能具有诸如 100 或 1000 之类的值 - 即如果我们遇到我上面描述的问题,如果乘以某个数量,高到足以溢出DOUBLE ) - 可能正在计算vialog会很慢吗?

4

3 回答 3

3

我想这会奏效...

SELECT IF(MOD(COUNT(data < 0),2)=1
        , EXP(SUM(LOG(data)))*-1
        , EXP(SUM(LOG(data))))
          x 
  FROM my_table;
于 2013-09-11T08:21:43.350 回答
2

如果您经常需要这种类型的计算,我建议您将符号和对数存储在单独的列中。

符号可以存储为1(对于正数)、-1(对于负数)和0(对于零)。

对数可以分配为零0(或任何其他值),但不应在计算中使用。

那么计算将是:

SELECT 
    CASE WHEN EXISTS (SELECT 1 FROM test WHERE <condition> AND datasign = 0)
         THEN 0
         ELSE (SELECT 1-2*(SUM(datasign=-1)%2) FROM test WHERE <condition>)
    END AS resultsign,

    CASE WHEN EXISTS (SELECT 1 FROM test WHERE <condition> AND datasign = 0)
         THEN -1            -- undefined log for result 0
         ELSE (SELECT SUM(datalog) FROM test WHERE <condition> AND datasign <> 0)
    END AS resultlog
  ;

这样,您就没有溢出问题。您可以检查resultlog它是否超出某些限制,或者只是尝试计算resultdata = resultsign * EXP(resultlog)并查看是否引发错误。

于 2013-09-11T08:17:31.960 回答
1

这个问题在低质量问题的海洋中是一个了不起的问题。谢谢你,即使阅读它也是一种乐趣。

精确

这个exp(log(a)+log(b))想法本身就是一个好主意。但是,在阅读“每个计算机科学家应该知道的关于浮点运算的知识”之后,请确保您使用DECIMALNUMERIC数据类型以确保您使用的是Precision Math,否则您的值将出人意料地不准确。对于几百万行,错误会很快增加!DECIMAL(根据 MySQL 文档)最多具有 65 位精度,而例如 64 位 IEEE754 浮点值最多只有 16 位 (log10(2^52) = 15.65) 精度!

溢出

根据MySQL doc 的相关部分

  • 整数溢出导致静默环绕。
  • DECIMAL溢出导致截断结果和警告。
  • 浮点溢出产生 NULL 结果。某些操作的溢出可能导致 +INF、-INF 或 NaN。

因此,您可以检测到浮点溢出是否会发生。

可悲的是,如果一系列操作会产生正确的值,适合所使用的数据类型,但在计算过程中至少有一个子结果不会,那么最终您将无法获得正确的值。

表现

过早的优化是万恶之源。试试看,如果速度很慢,请采取适当的措施。这样做可能不会很快,但仍可能比获得所有结果并在应用程序服务器上执行要快。只有测量才能决定哪个更快……

于 2013-09-11T08:13:59.363 回答