typia
Version:
Superfast runtime validators with only one line
1 lines • 13.5 kB
Source Map (JSON)
{"version":3,"file":"_randomMultiple.mjs","names":[],"sources":["../../src/internal/_randomMultiple.ts"],"sourcesContent":["import {\n _IDecimal,\n _IDecimalRatio,\n _decimalDecompose,\n _decimalDivide,\n _decimalGcd,\n _decimalIntegerStep,\n _decimalPower,\n _decimalToNumber,\n} from \"./_decimal\";\nimport { _isMultipleOf } from \"./_isMultipleOf\";\n\nexport const _randomMultiple = (props: {\n minimum: number;\n maximum: number;\n multipleOf: number;\n exclusiveMinimum: boolean;\n exclusiveMaximum: boolean;\n integer: boolean;\n}): number => {\n const step: _IDecimal | null = props.integer\n ? _decimalIntegerStep(props.multipleOf)\n : _decimalDecompose(props.multipleOf);\n if (step === null || step.coefficient <= BigInt(0))\n throw new Error(\"The multipleOf value must be a positive finite number.\");\n\n const lower: _IDecimalRatio | null = _decimalDivide(props.minimum, step);\n const upper: _IDecimalRatio | null = _decimalDivide(props.maximum, step);\n if (lower === null || upper === null)\n throw new Error(\"The random number range must be finite.\");\n const minimum: bigint = lowerBound(lower, props.exclusiveMinimum);\n const maximum: bigint = upperBound(upper, props.exclusiveMaximum);\n if (minimum > maximum)\n throw new Error(\"The range does not contain a multipleOf value.\");\n\n const selected: bigint = randomBigint(minimum, maximum);\n const candidates: bigint[] = unique([\n selected,\n minimum,\n maximum,\n clamp(BigInt(0), minimum, maximum),\n clamp(BigInt(1), minimum, maximum),\n clamp(BigInt(-1), minimum, maximum),\n ...nearby(selected, minimum, maximum),\n ]);\n for (const coefficient of candidates) {\n const value: number = _decimalToNumber({\n coefficient: step.coefficient * coefficient,\n exponent: step.exponent,\n });\n if (isValid(props, value)) return value;\n }\n const aligned: number | null = findRepresentableIntegerMultiple(props);\n if (aligned !== null) return aligned;\n const decimalAligned: number | null = findRepresentableDecimalMultiple(\n props,\n step,\n );\n if (decimalAligned !== null) return decimalAligned;\n throw new Error(\n \"The range does not contain a representable multipleOf value.\",\n );\n};\n\nconst isValid = (\n props: Parameters<typeof _randomMultiple>[0],\n value: number,\n): boolean =>\n Number.isFinite(value) &&\n (props.integer === false || Number.isInteger(value)) &&\n (props.exclusiveMinimum ? value > props.minimum : value >= props.minimum) &&\n (props.exclusiveMaximum ? value < props.maximum : value <= props.maximum) &&\n _isMultipleOf(value, props.multipleOf);\n\nconst findRepresentableDecimalMultiple = (\n props: Parameters<typeof _randomMultiple>[0],\n step: _IDecimal,\n): number | null => {\n const limit: bigint = BigInt(\"999999999999999\");\n for (let exponent = -324; exponent <= 308; ++exponent) {\n const unit: _IDecimal = { coefficient: BigInt(1), exponent };\n const lower: _IDecimalRatio | null = _decimalDivide(props.minimum, unit);\n const upper: _IDecimalRatio | null = _decimalDivide(props.maximum, unit);\n if (lower === null || upper === null) return null;\n\n const coefficientMinimum: bigint = max(\n -limit,\n lowerBound(lower, props.exclusiveMinimum),\n );\n const coefficientMaximum: bigint = min(\n limit,\n upperBound(upper, props.exclusiveMaximum),\n );\n if (coefficientMinimum > coefficientMaximum) continue;\n\n const coefficientStep: bigint = decimalCoefficientStep(step, exponent);\n const minimum: bigint = lowerBound(\n { numerator: coefficientMinimum, denominator: coefficientStep },\n false,\n );\n const maximum: bigint = upperBound(\n { numerator: coefficientMaximum, denominator: coefficientStep },\n false,\n );\n if (minimum > maximum) continue;\n\n const selected: bigint = randomBigint(minimum, maximum);\n for (const quotient of unique([\n selected,\n minimum,\n maximum,\n clamp(BigInt(0), minimum, maximum),\n ...nearby(selected, minimum, maximum),\n ])) {\n const value: number = _decimalToNumber({\n coefficient: coefficientStep * quotient,\n exponent,\n });\n if (isValid(props, value)) return value;\n }\n }\n return null;\n};\n\nconst decimalCoefficientStep = (step: _IDecimal, exponent: number): bigint => {\n const difference: number = exponent - step.exponent;\n if (difference >= 0) {\n const power: bigint = _decimalPower(difference);\n return step.coefficient / _decimalGcd(step.coefficient, power);\n }\n return step.coefficient * _decimalPower(-difference);\n};\n\nconst findRepresentableIntegerMultiple = (\n props: Parameters<typeof _randomMultiple>[0],\n): number | null => {\n const step: _IDecimal | null = _decimalIntegerStep(props.multipleOf);\n if (step === null) return null;\n const unit: _IDecimal = { coefficient: BigInt(1), exponent: 0 };\n const lower: _IDecimalRatio | null = _decimalDivide(props.minimum, unit);\n const upper: _IDecimalRatio | null = _decimalDivide(props.maximum, unit);\n if (lower === null || upper === null) return null;\n\n const minimum: bigint = lowerBound(lower, props.exclusiveMinimum);\n const maximum: bigint = upperBound(upper, props.exclusiveMaximum);\n if (minimum > maximum) return null;\n if (minimum <= BigInt(0) && maximum >= BigInt(0)) return 0;\n\n const candidate: bigint | null =\n minimum > BigInt(0)\n ? findPositiveAligned(minimum, maximum, step.coefficient)\n : (() => {\n const magnitude: bigint | null = findPositiveAligned(\n -maximum,\n -minimum,\n step.coefficient,\n );\n return magnitude === null ? null : -magnitude;\n })();\n if (candidate === null) return null;\n const value: number = Number(candidate);\n return isValid(props, value) ? value : null;\n};\n\nconst findPositiveAligned = (\n minimum: bigint,\n maximum: bigint,\n integerStep: bigint,\n): bigint | null => {\n const first: number = bitLength(minimum) - 1;\n const last: number = bitLength(maximum) - 1;\n for (let exponent = first; exponent <= last; ++exponent) {\n const bandMinimum: bigint = max(minimum, BigInt(1) << BigInt(exponent));\n const bandMaximum: bigint = min(\n maximum,\n (BigInt(1) << BigInt(exponent + 1)) - BigInt(1),\n );\n const quantum: bigint =\n exponent <= 52 ? BigInt(1) : BigInt(1) << BigInt(exponent - 52);\n const alignedStep: bigint =\n (integerStep / _decimalGcd(integerStep, quantum)) * quantum;\n const lower: bigint = lowerBound(\n { numerator: bandMinimum, denominator: alignedStep },\n false,\n );\n const upper: bigint = upperBound(\n { numerator: bandMaximum, denominator: alignedStep },\n false,\n );\n if (lower <= upper) return randomBigint(lower, upper) * alignedStep;\n }\n return null;\n};\n\nconst bitLength = (value: bigint): number => value.toString(2).length;\n\nconst min = (x: bigint, y: bigint): bigint => (x < y ? x : y);\nconst max = (x: bigint, y: bigint): bigint => (x > y ? x : y);\n\nconst lowerBound = (ratio: _IDecimalRatio, exclusive: boolean): bigint => {\n const quotient: bigint = ratio.numerator / ratio.denominator;\n const remainder: bigint = ratio.numerator % ratio.denominator;\n const ceiling: bigint =\n quotient + (remainder > BigInt(0) ? BigInt(1) : BigInt(0));\n return (\n ceiling + (exclusive && remainder === BigInt(0) ? BigInt(1) : BigInt(0))\n );\n};\n\nconst upperBound = (ratio: _IDecimalRatio, exclusive: boolean): bigint => {\n const quotient: bigint = ratio.numerator / ratio.denominator;\n const remainder: bigint = ratio.numerator % ratio.denominator;\n const floor: bigint =\n quotient - (remainder < BigInt(0) ? BigInt(1) : BigInt(0));\n return floor - (exclusive && remainder === BigInt(0) ? BigInt(1) : BigInt(0));\n};\n\nconst randomBigint = (minimum: bigint, maximum: bigint): bigint => {\n const scale: bigint = BigInt(1) << BigInt(53);\n const sample: bigint = BigInt(\n Math.min(\n Number(scale - BigInt(1)),\n Math.floor(Math.max(0, Math.random()) * Number(scale)),\n ),\n );\n return minimum + ((maximum - minimum + BigInt(1)) * sample) / scale;\n};\n\nconst clamp = (value: bigint, minimum: bigint, maximum: bigint): bigint =>\n value < minimum ? minimum : value > maximum ? maximum : value;\n\nconst nearby = (\n selected: bigint,\n minimum: bigint,\n maximum: bigint,\n): bigint[] => {\n const output: bigint[] = [];\n for (let distance = BigInt(1); distance <= BigInt(32); ++distance) {\n if (selected - distance >= minimum) output.push(selected - distance);\n if (selected + distance <= maximum) output.push(selected + distance);\n }\n return output;\n};\n\nconst unique = (values: bigint[]): bigint[] => [...new Set(values)];\n"],"mappings":"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"}