* Return the "rank", the order in which the expression should be * sorted.
(expr: Expression)
| 204 | 'constant', |
| 205 | 'symbol', |
| 206 | 'multiply', |
| 207 | 'divide', |
| 208 | 'add', |
| 209 | 'trig', |
| 210 | 'fn', |
| 211 | 'power', |
| 212 | 'string', |
| 213 | 'object', |
| 214 | 'other', |
| 215 | ] as const; |
| 216 | export type Rank = (typeof RANKS)[number]; |
| 217 | |
| 218 | /** |
| 219 | * Total three-way comparison of two floats suitable for a comparator. |
| 220 | * |
| 221 | * Unlike `af - bf`, this is a *total* order: it never returns `NaN`. Any |
| 222 | * `NaN` operand sorts after all real numbers (and two `NaN`s compare equal), |
| 223 | * so canonical ordering stays deterministic and permutation-invariant even |
| 224 | * when `NaN` is present. |
| 225 | */ |
| 226 | function compareFloat(a: number, b: number): number { |
| 227 | const aNaN = Number.isNaN(a); |
| 228 | const bNaN = Number.isNaN(b); |
| 229 | if (aNaN || bNaN) { |
| 230 | if (aNaN && bNaN) return 0; |
| 231 | return aNaN ? +1 : -1; |
| 232 | } |
| 233 | if (a < b) return -1; |
| 234 | if (a > b) return +1; |
| 235 | return 0; |
| 236 | } |
| 237 | |
| 238 | /** |
| 239 | * Return the "rank", the order in which the expression should be |
| 240 | * sorted. |
| 241 | */ |
| 242 | function rank(expr: Expression): Rank { |
| 243 | if (isNumber(expr)) { |
| 244 | if (typeof expr.numericValue === 'number') { |
| 245 | if (Number.isNaN(expr.numericValue)) return 'nan'; |
| 246 | return Number.isInteger(expr.numericValue) ? 'integer' : 'real'; |
| 247 | } |
| 248 | if (expr.numericValue.isNaN) return 'nan'; |
| 249 | const type = expr.numericValue.type; |
| 250 | if (type === 'integer' || type === 'finite_integer') return 'integer'; |
| 251 | if (type === 'rational' || type === 'finite_rational') return 'rational'; |
| 252 | if (type === 'real' || type === 'finite_real') return 'real'; |
| 253 | if (type === 'complex' || type === 'finite_complex') return 'complex'; |
| 254 | if (type === 'imaginary') return 'complex'; |
| 255 | if (type === 'finite_number') return 'complex'; |
| 256 | if (type === 'non_finite_number') return 'constant'; |
| 257 | if (type === 'number') return 'real'; |
| 258 | return 'other'; |
| 259 | } |
| 260 | |
| 261 | // Complex numbers |
| 262 | if (isSymbol(expr, 'ImaginaryUnit')) return 'complex'; |
| 263 |
no test coverage detected