num.c (5745B)
1 2 #include <stdio.h> 3 #include <assert.h> 4 #include <stdlib.h> 5 #include <math.h> 6 #include <inttypes.h> 7 #include <string.h> 8 #include "num.h" 9 10 void 11 num_init(struct num *num) { 12 num->type = TYPE_INT; 13 num->unit = UNIT_BTC; 14 num->intval = 0LL; 15 } 16 17 void 18 error_any() { 19 fprintf(stderr, "error: --price argument required when using arbitrary units\n"); 20 exit(1); 21 } 22 23 static int64_t 24 num_to_msat(struct num *num) { 25 double anyval = 1.0; 26 27 if (num->type == TYPE_FLOAT) { 28 double val = num->floatval; 29 switch (num->unit) { 30 case UNIT_OTHER: 31 if (g_other.unit == UNIT_NONE) error_any(); 32 double other = 1.0/(g_other.type == TYPE_FLOAT ? g_other.floatval 33 : (double)g_other.intval); 34 return (int64_t)(val * BTC * other); 35 case UNIT_MSATOSHI: 36 return (int64_t)val; 37 case UNIT_SATOSHI: 38 return (int64_t)(val * SATOSHI); 39 case UNIT_FINNEY: 40 return (int64_t)(val * FINNEY); 41 case UNIT_BITS: 42 return (int64_t)(val * BITS); 43 case UNIT_MBTC: 44 return (int64_t)(val * MBTC); 45 case UNIT_BTC: 46 return (int64_t)(val * BTC); 47 case UNIT_NONE: 48 assert(!"got UNIT_NONE in num_to_msat"); 49 } 50 } 51 52 int64_t val = num->intval; 53 switch (num->unit) { 54 case UNIT_MSATOSHI: 55 return val; 56 case UNIT_SATOSHI: 57 return val * SATOSHI; 58 case UNIT_FINNEY: 59 return val * FINNEY; 60 case UNIT_BITS: 61 return val * BITS; 62 case UNIT_MBTC: 63 return val * MBTC; 64 case UNIT_OTHER: 65 if (g_other.unit != UNIT_OTHER) error_any(); 66 anyval = g_other.type == TYPE_FLOAT? 67 g_other.floatval : (double)g_other.intval; 68 case UNIT_BTC: 69 return val * BTC*(1.0/anyval); 70 case UNIT_NONE: 71 assert(!"got UNIT_NONE in num_to_msat"); 72 } 73 } 74 75 #define num_op (op) 76 77 void 78 num_add(struct num *dst, struct num *a, struct num *b) { 79 dst->type = TYPE_INT; 80 dst->unit = UNIT_MSATOSHI; 81 dst->intval = num_to_msat(a) + num_to_msat(b); 82 } 83 84 85 void 86 num_sub(struct num *dst, struct num *a, struct num *b) { 87 dst->type = TYPE_INT; 88 dst->unit = UNIT_MSATOSHI; 89 dst->intval = num_to_msat(a) - num_to_msat(b); 90 } 91 92 int64_t 93 unit_msat_multiple(enum unit format) { 94 switch (format) { 95 case UNIT_MSATOSHI: return MSATOSHI; 96 case UNIT_SATOSHI: return SATOSHI; 97 case UNIT_FINNEY: return FINNEY; 98 case UNIT_BITS: return BITS; 99 case UNIT_MBTC: return MBTC; 100 case UNIT_OTHER: 101 if (g_other.unit != UNIT_OTHER) error_any(); 102 return BTC / (g_other.type == TYPE_FLOAT 103 ? g_other.floatval 104 : g_other.intval); 105 case UNIT_BTC: return BTC; 106 case UNIT_NONE: assert(!"got UNIT_NONE in num_to_msat"); 107 } 108 } 109 110 void 111 num_mul(struct num *dst, struct num *a, struct num *b) { 112 assert(b->unit == UNIT_NONE); 113 dst->type = TYPE_INT; 114 dst->unit = UNIT_MSATOSHI; 115 int64_t num = num_to_msat(a); 116 switch (b->type) { 117 case TYPE_FLOAT: 118 dst->intval = (int64_t)(num * b->floatval); 119 double d = (double)num * b->floatval; 120 // FIXME: floating point sucks 121 if (d <= 1.000000000000001L && 0.99999999999999L <= d) dst->intval = 1LL; 122 break; 123 case TYPE_INT: 124 dst->intval = num * b->intval; 125 break; 126 } 127 } 128 129 void 130 num_div(struct num *dst, struct num *a, struct num *b) { 131 dst->type = TYPE_INT; 132 dst->unit = UNIT_MSATOSHI; 133 134 if (b->unit == UNIT_NONE) { 135 dst->intval = num_to_msat(a) / (b->type == TYPE_FLOAT? b->floatval 136 : b->intval); 137 } else if (a->unit == UNIT_NONE) { 138 assert(!"not working yet"); 139 /* dst->type = TYPE_FLOAT; */ 140 /* dst->unit = b->unit; */ 141 /* double ad = a->type == TYPE_FLOAT? a->floatval : (double)a->intval; */ 142 /* int64_t bmsat = num_to_msat(b); */ 143 } 144 else { 145 assert(!"shouldnt happen"); 146 } 147 } 148 149 void 150 num_init_float(struct num *num, double d, enum unit unit) { 151 num_init(num); 152 num->floatval = d; 153 num->type = TYPE_FLOAT; 154 num->unit = unit; 155 if (unit != UNIT_NONE) num_assign(num, num); 156 } 157 158 void 159 num_init_int(struct num *num, int64_t val, enum unit unit) { 160 num_init(num); 161 num->intval = val; 162 num->type = TYPE_INT; 163 num->unit = unit; 164 if (unit != UNIT_NONE) num_assign(num, num); 165 } 166 167 void 168 num_assign(struct num *dst, struct num *a) { 169 struct num num; 170 num.type = TYPE_INT; 171 num.unit = UNIT_MSATOSHI; 172 num.intval = num_to_msat(a); 173 *dst = num; 174 } 175 176 static void 177 trim_zeros (char *s, int n) 178 { 179 char *p; 180 int count; 181 182 p = strchr (s,'.'); // Find decimal point, if any. 183 if (p != NULL) { 184 count = n; // Adjust for more or less decimals. 185 while (count >= 0) { // Maximum decimals allowed. 186 count--; 187 if (*p == '\0') // If there's less than desired. 188 break; 189 p++; // Next character. 190 } 191 192 *p-- = '\0'; // Truncate string. 193 while (*p == '0') // Remove trailing zeros. 194 *p-- = '\0'; 195 196 if (*p == '.') { // If all decimals were zeros, remove ".". 197 *p = '\0'; 198 } 199 } 200 } 201 202 void 203 num_print(struct num *num, enum unit format, char *unitname, int print_unit) { 204 static char buffer[255]; 205 int64_t msat_multiple = unit_msat_multiple(format); 206 207 208 double d = num->type == TYPE_FLOAT? num->floatval : (double)num->intval; 209 d /= (double)msat_multiple; 210 sprintf (buffer, "%.11f", d); 211 trim_zeros(buffer, 12); 212 printf("%s", buffer); 213 214 if (print_unit) 215 printf(" %s", unitname? unitname : unit_name(format)); 216 217 printf("\n"); 218 } 219 220 221 222 char * 223 unit_name(enum unit unit) { 224 switch (unit) { 225 case UNIT_MSATOSHI: return "msat"; 226 case UNIT_SATOSHI: return "sat"; 227 case UNIT_FINNEY: return "finney"; 228 case UNIT_BITS: return "bits"; 229 case UNIT_MBTC: return "mBTC"; 230 case UNIT_BTC: return "BTC"; 231 case UNIT_OTHER: return g_other_name; 232 case UNIT_NONE: assert(!"got UNIT_NONE in num_to_msat"); 233 default: 234 assert(!"missing unit"); 235 } 236 }