SO,
问题
我有行乘法的问题。在SQL中,有一个SUM()
函数,它计算行集的某些字段的总和。我希望得到乘法,即表格
+------+ | data | +------+ | 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
未定义 - 我需要在计算整个表达式之前计算负号。针对此示例数据和查询in this fiddle。
另一个缺点是我们需要找出列值中是否有0(因为它是一个样本,在实际情况下,我将选择产品用于某些条件的表行的子集 - 即我不能简单从我的表中删除0-s,因为结果零产品是某些行子集的有效和预期结果)
具体细节信息
现在,最后,我的问题主要部分:当我们有这样的表达时如何处理情况:X*Y*Z
和X < MAXF
,Y<MAXF
,X*Y>MAXF
和{ {1}} - 所以我们可能有数据类型溢出(这里X*Y*Z<MAXF
是 double MySQL数据类型的限制)。样本为here。上面的查询效果很好,但我能否始终确保它能正确处理?即当某些子产品导致溢出,但整个产品没问题(没有溢出)时,可能会出现另一种溢出问题。
或者可能有其他方法可以找到行产品?此外,在表中可能有数百万条记录(MAXF
主要是,但可能有100或1000等值 - 即如果我们有一个数量,如果乘以一定数量,则高到足以溢出 DOUBLE 我上面已经描述过的问题 - 可能通过-1.1<X<=1.1
计算会很慢吗?
答案 0 :(得分:3)
我想这会奏效......
SELECT IF(MOD(COUNT(data < 0),2)=1
, EXP(SUM(LOG(data)))*-1
, EXP(SUM(LOG(data))))
x
FROM my_table;
答案 1 :(得分: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)
并查看是否出现错误。
答案 2 :(得分:1)
这个问题在低质量的海洋中是一个了不起的问题。谢谢你,即使阅读它也很愉快。
<强>精密强>
exp(log(a)+log(b))
这个想法本身就是一个好主意。但是,在阅读"What Every Computer Scientist Should Know About Floating-Point Arithmetic"后,请确保使用DECIMAL
or NUMERIC
数据类型以确保您使用Precision Math,否则您的值将会出乎意料地不准确。对于几百万行,错误可以非常快地加起来! DECIMAL
(根据MySQL文档)最多具有65位精度,而例如64位IEEE754浮点值最多只能有16位数(log10(2 ^ 52)= 15.65)精度!
<强>溢出强>
根据relevant part of the MySQL doc:
- 整数溢出导致无声环绕。
- DECIMAL 溢出会导致截断结果和警告。
- 浮点溢出会产生NULL结果。某些操作的溢出可能导致+ INF,-INF或NaN。
因此,如果发生浮点溢出,您可以检测到浮点溢出。
遗憾的是,如果一系列操作会产生正确的值,适合所使用的数据类型,但计算过程中至少有一个子结果不适合,那么最后你将得不到正确的值。
<强>性能强>
过早优化是万恶之源。尝试一下,如果速度很慢,请采取适当的措施。这样做可能不会很快,但仍然可能比获取所有结果更快,并且在应用程序服务器上执行此操作。只有测量可以决定哪个更快......