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'