|
|
@@ -0,0 +1,176 @@
|
|
|
+from decimal import Decimal, getcontext
|
|
|
+
|
|
|
+# 增加精度以处理更多小数位,如果需要的话
|
|
|
+getcontext().prec = 50
|
|
|
+
|
|
|
+def decimal_to_string_no_scientific(d_value: Decimal) -> str:
|
|
|
+ """
|
|
|
+ 将 Decimal 类型转换为无科学计数法的字符串。
|
|
|
+ 尝试使用 normalize() 确保消除科学计数法,并保持所有有效数字。
|
|
|
+ """
|
|
|
+ if not isinstance(d_value, Decimal):
|
|
|
+ raise TypeError("Input must be a Decimal type.")
|
|
|
+
|
|
|
+ # normalize() 方法可以移除尾随的0并调整指数,但不会强制转换为非科学计数法
|
|
|
+ # 转换为字符串时,Python的Decimal默认会尽可能不使用科学计数法,
|
|
|
+ # 除非数字非常大或非常小。
|
|
|
+ # 对于极小的数,直接str()可能会出现科学计数法。
|
|
|
+
|
|
|
+ # 更稳妥的方法是,将其格式化为字符串,并确保它没有科学计数法。
|
|
|
+ # 我们可以通过精确控制小数点后的位数来避免科学计数法。
|
|
|
+ # 但由于我们不知道具体需要多少位,所以直接用str()通常是最直接的。
|
|
|
+
|
|
|
+ s_value = str(d_value)
|
|
|
+
|
|
|
+ # 检查是否包含科学计数法标识 'e' 或 'E'
|
|
|
+ if 'e' in s_value.lower():
|
|
|
+ # 如果包含,我们需要更精细地处理
|
|
|
+ # 先将其标准化,然后转换为字符串
|
|
|
+ normalized_d = d_value.normalize()
|
|
|
+ s_value = str(normalized_d)
|
|
|
+
|
|
|
+ # 即使normalize(),对于非常大的或非常小的数,str()仍然可能使用科学计数法。
|
|
|
+ # 强制转换为非科学计数法,可以通过指定一个非常大的小数点后位数来实现。
|
|
|
+ # 这里,我们查找小数点后的最大位数来避免信息丢失。
|
|
|
+ if 'e' in s_value.lower(): # 再次检查,以防normalize()后仍有
|
|
|
+ # 通常,当Decimal转换成字符串时显示科学计数法,说明它要么很大,要么很小。
|
|
|
+ # 对于很小的数,我们通过扩展精度来确保所有零被显示。
|
|
|
+ # 例如:0.00000001
|
|
|
+ # 可以通过创建负指数的Decimal来表示小数点后的位数
|
|
|
+ # 例如 Decimal(10)**(-N)
|
|
|
+ # 但一个更通用的方法是,将其转换为字符串后,如果发现'e',则手动解析和格式化。
|
|
|
+
|
|
|
+ # Decimal模块通常在str()时会避免科学计数法,除非绝对必要。
|
|
|
+ # 如果出现,尝试使用to_eng_string(),它可能看起来更像非科学计数法。
|
|
|
+ # 但最直接的是手动控制精度
|
|
|
+ s_value = _format_decimal_to_plain_string(d_value)
|
|
|
+
|
|
|
+ return s_value
|
|
|
+
|
|
|
+def _format_decimal_to_plain_string(d_value: Decimal) -> str:
|
|
|
+ """
|
|
|
+ 辅助函数:将Decimal强制转换为无科学计数法的字符串。
|
|
|
+ 通过动态确定小数点后的位数。
|
|
|
+ """
|
|
|
+ s = str(d_value)
|
|
|
+ if 'E' in s or 'e' in s:
|
|
|
+ # 提取指数部分
|
|
|
+ if 'E' in s:
|
|
|
+ parts = s.split('E')
|
|
|
+ else:
|
|
|
+ parts = s.split('e')
|
|
|
+
|
|
|
+ coefficient = parts[0]
|
|
|
+ exponent = int(parts[1])
|
|
|
+
|
|
|
+ # 处理负号
|
|
|
+ sign = ""
|
|
|
+ if coefficient.startswith('-'):
|
|
|
+ sign = "-"
|
|
|
+ coefficient = coefficient[1:]
|
|
|
+
|
|
|
+ # 处理小数点
|
|
|
+ if '.' in coefficient:
|
|
|
+ int_part, frac_part = coefficient.split('.')
|
|
|
+ else:
|
|
|
+ int_part = coefficient
|
|
|
+ frac_part = ""
|
|
|
+
|
|
|
+ # 根据指数移动小数点
|
|
|
+ if exponent >= 0:
|
|
|
+ # 扩大整数部分,补零
|
|
|
+ num_zeros = exponent - len(frac_part)
|
|
|
+ if num_zeros >= 0:
|
|
|
+ result = int_part + frac_part + '0' * num_zeros
|
|
|
+ else:
|
|
|
+ result = int_part + frac_part[:exponent] + '.' + frac_part[exponent:]
|
|
|
+ else: # exponent < 0
|
|
|
+ # 缩小整数部分,在前面补零
|
|
|
+ abs_exponent = abs(exponent)
|
|
|
+ if len(int_part) <= abs_exponent:
|
|
|
+ # 例如 1.23E-4 -> 0.000123
|
|
|
+ result = '0.' + '0' * (abs_exponent - len(int_part)) + int_part + frac_part
|
|
|
+ else:
|
|
|
+ # 例如 123.45E-1 -> 12.345
|
|
|
+ insert_pos = len(int_part) - abs_exponent
|
|
|
+ result = int_part[:insert_pos] + '.' + int_part[insert_pos:] + frac_part
|
|
|
+
|
|
|
+ # 移除结果中可能的尾随小数点(例如 '123.' -> '123')
|
|
|
+ if result.endswith('.'):
|
|
|
+ result = result[:-1]
|
|
|
+
|
|
|
+ # 移除结果中多余的前导零(例如 '007' -> '7',但保留 '0.xx')
|
|
|
+ if result != '0' and result.startswith('0') and not result.startswith('0.'):
|
|
|
+ result = result.lstrip('0')
|
|
|
+ if not result: # 如果只剩下0,则保留一个0
|
|
|
+ result = '0'
|
|
|
+
|
|
|
+ return sign + result
|
|
|
+ else:
|
|
|
+ return s
|
|
|
+
|
|
|
+# ---- 测试 ----
|
|
|
+if __name__ == "__main__":
|
|
|
+ # 示例 1: 原始示例中成功的 case
|
|
|
+ params1 = {
|
|
|
+ 'price': Decimal('0.0004098'),
|
|
|
+ 'quantity': 160000,
|
|
|
+ 'side': 'SELL',
|
|
|
+ 'symbol': 'HASHAIUSDT',
|
|
|
+ 'type': 'LIMIT'
|
|
|
+ }
|
|
|
+ price_str1 = decimal_to_string_no_scientific(params1['price'])
|
|
|
+ print(f"Original Decimal: {params1['price']}, Converted String: '{price_str1}'")
|
|
|
+ # 预期输出: '0.0004098'
|
|
|
+
|
|
|
+ # 示例 2: 原始示例中失败的 case
|
|
|
+ params2 = {
|
|
|
+ 'price': Decimal('1.617015400E-8'),
|
|
|
+ 'quantity': 320000000,
|
|
|
+ 'side': 'BUY',
|
|
|
+ 'symbol': 'MANYUSDT',
|
|
|
+ 'type': 'LIMIT'
|
|
|
+ }
|
|
|
+ price_str2 = decimal_to_string_no_scientific(params2['price'])
|
|
|
+ print(f"Original Decimal: {params2['price']}, Converted String: '{price_str2}'")
|
|
|
+ # 预期输出: '0.00000001617015400'
|
|
|
+
|
|
|
+ # 更多测试用例
|
|
|
+ # 较大整数
|
|
|
+ d3 = Decimal('12345678901234567890.1')
|
|
|
+ s3 = decimal_to_string_no_scientific(d3)
|
|
|
+ print(f"Original Decimal: {d3}, Converted String: '{s3}'")
|
|
|
+ # 预期输出: '12345678901234567890.1'
|
|
|
+
|
|
|
+ # 较大整数带科学计数法表示
|
|
|
+ d4 = Decimal('1.23E+10')
|
|
|
+ s4 = decimal_to_string_no_scientific(d4)
|
|
|
+ print(f"Original Decimal: {d4}, Converted String: '{s4}'")
|
|
|
+ # 预期输出: '12300000000'
|
|
|
+
|
|
|
+ # 较小浮点数,且 str() 本身可能显示科学计数法
|
|
|
+ d5 = Decimal('0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000') # 这是一个非常非常小的数
|
|
|
+ s5 = decimal_to_string_no_scientific(d5)
|
|
|
+ print(f"Original Decimal: {d5}, Converted String: '{s5}'")
|
|
|
+ # 预期输出: 应该是一长串0.000...000后跟着一个1
|
|
|
+
|
|
|
+ # 负数
|
|
|
+ d6 = Decimal('-1.2345E-5')
|
|
|
+ s6 = decimal_to_string_no_scientific(d6)
|
|
|
+ print(f"Original Decimal: {d6}, Converted String: '{s6}'")
|
|
|
+ # 预期输出: '-0.000012345'
|
|
|
+
|
|
|
+ d7 = Decimal('0')
|
|
|
+ s7 = decimal_to_string_no_scientific(d7)
|
|
|
+ print(f"Original Decimal: {d7}, Converted String: '{s7}'")
|
|
|
+ # 预期输出: '0'
|
|
|
+
|
|
|
+ d8 = Decimal('-0.00') # 保持尾随的0
|
|
|
+ s8 = decimal_to_string_no_scientific(d8)
|
|
|
+ print(f"Original Decimal: {d8}, Converted String: '{s8}'")
|
|
|
+ # 预期输出: '-0.00'
|
|
|
+
|
|
|
+ d9 = Decimal('12300.00')
|
|
|
+ s9 = decimal_to_string_no_scientific(d9)
|
|
|
+ print(f"Original Decimal: {d9}, Converted String: '{s9}'")
|
|
|
+ # 预期输出: '12300.00'
|