总结一下
Java/Scala中的
- scala.math.BigDecimal
- scala.math.BigInt
- java.math.BigDecimal
- java.math.BigInteger
Python中的 - int
- decimal.Decimal
以上列出的数据类型,在内存允许的情况下作算术运算时是没有数值范围上限的
spark中的DecimalType就不一样了,参考源码:
val MAX_PRECISION = 38
val MAX_SCALE = 38
val SYSTEM_DEFAULT: DecimalType = DecimalType(MAX_PRECISION, 18)
val USER_DEFAULT: DecimalType = DecimalType(10, 0)
遇到的问题:
有一种需求,数值岂止是天文数字且要求保证精度(decimal(38,18))。沉默不语的DoubleType被喷了个狗血淋头(:
丢一个IEEE二进制浮点数算术标准(IEEE 754)可自行Google搜索研究
需求已经提出了,实现思路:
pyspark中对于浮点数值运算时,定义udf,在udf内部通过decimal进行计算,最终返回StringType或返回DecimalType(38,18)
# eval('%s * %s')
# eval('pow(%s,%s)')
# eval('%s + %s')
# eval函数使用参考https://www.programiz.com/python-programming/methods/built-in/eval
from decimal import *
decimalMaxvalue = Decimal('99999999999999999999.999999999999999999')
def calcByDecimal(x, y, myexpr):
expr = myexpr % ("Decimal('" + str(x) + "')", "Decimal('" + str(y) + "')")
result = eval(expr,{'Decimal': Decimal})
if (result > decimalMaxvalue):
# 可自行控制返回的decimal大小或者不控制大小即返回stringtype
return decimalMaxvalue
else:
return result
# 或者
def calcByDecimal(list, myexpr):
tup = ()
for e in list:
e = "Decimal('" + str(e) + "')"
tup = tup + (e,)
expr = myexpr % tup
result = eval(expr,{'Decimal': Decimal})
if (result > decimalMaxvalue):
return decimalMaxvalue
else:
return result
# from pyspark.sql.types import DecimalType
# import pyspark.sql.functions as F
# from pyspark.sql.functions import udf
# myudf = udf(calcByDecimal, DecimalType(38, 18))