금액 정밀도와 소수 자릿수: 조금 적게 보낼 때 손해가 나는 지점
2026-10-25 측정: 19와 19.9 USDT는 원금 4.7% 차이로 받는 양 11.0% 차이, 100과 100.000001은 마지막 자리까지 동일. 답을 만드는 코드를 읽어 받는 양 8자리, 환율 유효 8자리, 읽는 동안 움직이는 상하한을 확인합니다.
'조금 적게'에는 두 가지가 있다. 2026-10-25 18:06:17 UTC, 자체 견적 엔드포인트는 19 USDT-TRC20을 0.01334439 XMR로 평가했습니다. 2초 뒤 19.9 USDT는 0.01481818. 금액을 4.7% 늘려 모네로는 11.0% 늘었습니다. 하한에 붙은 위치에서 부족분은 비례하지 않습니다. 그 40초 전 같은 엔드포인트는 100 USDT와 100.000001 USDT를 마지막 자리까지 동일하게 돌려줬습니다. 0.14598334 XMR, 환율 0.0014598334. 1마이크로 USDT는 아무것도 바꾸지 못했습니다. 둘 다 맞는 결과이고, 함께 '조금 적게'의 의미를 규정합니다. 하한을 깨면 비싸고, 마지막 소수 자리에서는 보이지 않습니다. (XMR→USDT 출구 루트)
모든 자산에는 더 쪼갤 수 없는 최소 단위가 있다. 1 BTC는 100,000,000 satoshi, 오늘 80,703달러 기준 1 satoshi는 0.000807달러. 1 XMR은 1,000,000,000,000 piconero, 1 piconero는 0.0000000006달러. 1 ETH는 10^18 wei, 1 wei는 약 0.0000000000000024달러. ZEC의 zatoshi는 1e-8, LTC의 litoshi도 1e-8, SOL의 lamport는 1e-9, TRX의 sun은 1e-6, USDT는 트론과 이더리움 모두 6자리로 최소 단위가 0.000001달러입니다. 표시 관습이 아니라 원장이 움직일 수 있는 최소 수입니다. 보이는 모든 견적은 그 정수 개수를 반올림한 버전입니다. (SOL to XMR guide)
견적은 8자리로 잘린다. 견적 라우트는 받는 양에 `Number(best.toAmount.toFixed(8))`을, 환율에 `Number(best.rate.toPrecision(8))`을 반환하고 주문 라우트도 가격을 고정할 때 같은 8자리로 기록합니다. 위의 1마이크로 USDT가 사라진 이유입니다. 0.000001 USDT × 약 0.00146 = 1.5e-12 XMR로 8번째 자리에 전혀 닿지 않습니다. 반올림 손실은 최대 0.00000001 XMR, 오늘 가격으로 약 0.000006달러. 돈으로는 무시할 수 있지만 더 중요한 것을 결정합니다. 약속 자체가 소수 8자리까지만 가지고, 반대편 체인은 정수를 기록한다는 점입니다. (XMR→USDT 출구 루트)
자릿수는 거짓말을 한다. 같은 엔드포인트가 1 XMR에 595.698 USDT, 환율에 0.0014615927, 상한에 293.397277258162 XMR을 출력했습니다. 세 가지 정밀도처럼 보이지만 실제로는 두 규칙과 하나의 포매터입니다. 환율은 항상 유효숫자 8자리라서 소수 자릿수는 크기에 따라 달라집니다. JSON 숫자는 끝의 0을 버리므로 595.698은 실제로 595.69800000입니다. 소수점 아래 자릿수를 세지 말고 규칙을 읽으세요. 받는 양 8자리, 환율 유효 8자리, 상하한은 라우트 엔진 출력 그대로 — 그래서 같은 엔드포인트에서 모네로 상한은 12자리, USDT 하한은 6자리로 나옵니다. (XMR→USDT 출구 루트)
상하한은 읽는 동안에도 움직인다. 18:02에 USDT-TRC20→XMR 하한은 19.801624, 상한은 176,509.209306이었습니다. 18:06에는 19.786762와 176,443.886799, 18:10에는 19.791362와 176,464.859757이 되었습니다. 아무도 파라미터를 건드리지 않았습니다. 두 경계 모두 출금 쪽에서 역산되어 환율을 따라갑니다. 반대 방향에서는 상한이 293.397277258162 XMR, 하한이 0.02974636이었습니다. 1토큰을 보내면 견적 대신 `amount below minimum` 구조화 오류가 두 경계와 함께 돌아옵니다. 결론은 단순합니다. 페이지에서 복사한 숫자(이 글의 숫자 포함)는 스냅숏이고, 보내기 직전에 다시 받아야 합니다. (XMR→USDT 출구 루트)
그 아래 원장은 정수다. 오늘 18:00:31 UTC 비트코인 블록 973,103에는 25개 트랜잭션, 41개 출력이 있었습니다. 최대 2,449,754,800 satoshi, 최소 0인 OP_RETURN. 블록 전체 수수료는 32,787 satoshi / 5,140 vB, 6.379 sat/vB로 약 26.46달러였습니다. 트론 블록 87,426,048은 536개 트랜잭션, 그중 131개가 USDT 전송이었고 최소가 3,375,404 기본 단위=3.375404 USDT, 최대가 정확히 100,000.000000이었습니다. 모네로 블록 3,791,996은 42개 트랜잭션 87,296바이트, 보상은 600,030,720,000 원자 단위=0.60003072 XMR. 어떤 체인도 '3.375404개'를 저장하지 않습니다. 정수를 저장하고 소수점은 가장자리에서 붙이는 표시 결정입니다. (XMR→USDT 출구 루트)
부동소수가 실제로 무는 지점. Node에서 네 줄이면 버그 종류가 보입니다. `0.1 + 0.2`는 0.30000000000000004. `1.15 * 100`은 114.99999999999999 — 'Max' 버튼이 잔액에 가격을 곱하면 잔액보다 아주 조금 적고, 더 나쁘게는 하한보다도 조금 적은 값이 나옵니다. `(0.000181501).toFixed(8)`은 0.00018150을 반환하며 9번째 자리를 거부하지 않고 조용히 버립니다. 그리고 10^18 wei는 2^53보다 커서 자바스크립트는 wei를 정확히 셀 수 없습니다. 그 크기에서는 최대 안전 정수에 1을 더해도 같은 수가 나옵니다. 그래서 금액은 정수나 문자열로 다루고 표시하는 순간에만 소수로 바꿉니다.
정밀도를 위한 6단계. 1) 계산 전에 최소 단위로 바꿉니다. 100 USDT는 100,000,000단위, 1 XMR은 1,000,000,000,000 piconero입니다. 2) 실제로 보낼 순액으로 계산합니다. 거래소 출금은 수수료를 먼저 떼므로 순액을 읽습니다. 3) 'Max'를 그대로 견적 금액으로 쓰지 않습니다. 부동소수 뺄셈이라 잔여값이 남습니다. 4) 하한에서 측정 가능한 한 단계 위를 잡습니다. 하한 19.79면 20을 보냅니다. 하한은 움직이고, 거절되면 1분을 잃습니다. 5) 자산 자체의 정밀도를 넘지 않습니다. BTC 9번째 자리는 존재하지 않으므로 반올림하는 쪽이 버립니다. 6) 대조는 정수로 합니다. XMR 1e-8 차이는 0.000006달러지만, 100 USDT 입금의 1e-6 차이는 이미 신고한 금액과 다른 돈입니다. (XMR→USDT 출구 루트)
창구에서 이것이 뜻하는 것. 스왑의 정밀도는 12자리를 외우는 것이 아니라 눈앞의 숫자 중 무엇이 정확한지 아는 것입니다. 체인의 정수, 주문에 적힌 소수 8자리 약속, 유효 8자리 환율, 그리고 계속 움직이는 상하한. 19와 19.9 USDT의 차이는 받는 양의 11%. 100과 100.000001의 차이는 0이며, 답의 분해능보다 작기 때문입니다. 같은 물리이고, 구별할 수 있으면 틀린 쪽에 돈을 내지 않게 됩니다. 자기 금액으로 견적을 받고, 하한을 확인하고, 순액을 보내고, 실제로 받은 정수로 8자리 약속을 대조하세요. (XMR→USDT 출구 루트)