@clayroach/effect 3.19.14-source-capture.8 → 3.19.14-source-trace.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SourceLocation/package.json +6 -0
- package/dist/cjs/Effect.js +2 -28
- package/dist/cjs/Effect.js.map +1 -1
- package/dist/cjs/FiberRef.js +12 -1
- package/dist/cjs/FiberRef.js.map +1 -1
- package/dist/cjs/Layer.js +2 -24
- package/dist/cjs/Layer.js.map +1 -1
- package/dist/cjs/RuntimeFlags.js +1 -29
- package/dist/cjs/RuntimeFlags.js.map +1 -1
- package/dist/cjs/SourceLocation.js +60 -0
- package/dist/cjs/SourceLocation.js.map +1 -0
- package/dist/cjs/Tracer.js +1 -15
- package/dist/cjs/Tracer.js.map +1 -1
- package/dist/cjs/Utils.js +1 -1
- package/dist/cjs/Utils.js.map +1 -1
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/internal/clock.js +1 -1
- package/dist/cjs/internal/clock.js.map +1 -1
- package/dist/cjs/internal/core.js +17 -50
- package/dist/cjs/internal/core.js.map +1 -1
- package/dist/cjs/internal/effect/circular.js +18 -30
- package/dist/cjs/internal/effect/circular.js.map +1 -1
- package/dist/cjs/internal/fiberRuntime.js +16 -65
- package/dist/cjs/internal/fiberRuntime.js.map +1 -1
- package/dist/cjs/internal/layer/circular.js +1 -5
- package/dist/cjs/internal/layer/circular.js.map +1 -1
- package/dist/cjs/internal/layer.js +1 -3
- package/dist/cjs/internal/layer.js.map +1 -1
- package/dist/cjs/internal/logger.js +25 -2
- package/dist/cjs/internal/logger.js.map +1 -1
- package/dist/cjs/internal/runtimeFlags.js +2 -11
- package/dist/cjs/internal/runtimeFlags.js.map +1 -1
- package/dist/cjs/internal/tracer.js +1 -114
- package/dist/cjs/internal/tracer.js.map +1 -1
- package/dist/dts/Config.d.ts +2 -2
- package/dist/dts/Config.d.ts.map +1 -1
- package/dist/dts/Effect.d.ts +8 -29
- package/dist/dts/Effect.d.ts.map +1 -1
- package/dist/dts/FiberRef.d.ts +12 -0
- package/dist/dts/FiberRef.d.ts.map +1 -1
- package/dist/dts/Layer.d.ts +0 -22
- package/dist/dts/Layer.d.ts.map +1 -1
- package/dist/dts/RuntimeFlags.d.ts +0 -28
- package/dist/dts/RuntimeFlags.d.ts.map +1 -1
- package/dist/dts/SourceLocation.d.ts +88 -0
- package/dist/dts/SourceLocation.d.ts.map +1 -0
- package/dist/dts/Tracer.d.ts +0 -15
- package/dist/dts/Tracer.d.ts.map +1 -1
- package/dist/dts/index.d.ts +6 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/internal/core.d.ts.map +1 -1
- package/dist/dts/internal/layer.d.ts.map +1 -1
- package/dist/dts/internal/runtimeFlags.d.ts.map +1 -1
- package/dist/esm/Effect.js +0 -26
- package/dist/esm/Effect.js.map +1 -1
- package/dist/esm/FiberRef.js +11 -0
- package/dist/esm/FiberRef.js.map +1 -1
- package/dist/esm/Layer.js +0 -22
- package/dist/esm/Layer.js.map +1 -1
- package/dist/esm/RuntimeFlags.js +0 -28
- package/dist/esm/RuntimeFlags.js.map +1 -1
- package/dist/esm/SourceLocation.js +51 -0
- package/dist/esm/SourceLocation.js.map +1 -0
- package/dist/esm/Tracer.js +0 -14
- package/dist/esm/Tracer.js.map +1 -1
- package/dist/esm/Utils.js +1 -1
- package/dist/esm/Utils.js.map +1 -1
- package/dist/esm/index.js +6 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/clock.js +1 -1
- package/dist/esm/internal/clock.js.map +1 -1
- package/dist/esm/internal/core.js +12 -45
- package/dist/esm/internal/core.js.map +1 -1
- package/dist/esm/internal/effect/circular.js +18 -30
- package/dist/esm/internal/effect/circular.js.map +1 -1
- package/dist/esm/internal/fiberRuntime.js +13 -60
- package/dist/esm/internal/fiberRuntime.js.map +1 -1
- package/dist/esm/internal/layer/circular.js +0 -4
- package/dist/esm/internal/layer/circular.js.map +1 -1
- package/dist/esm/internal/layer.js +0 -2
- package/dist/esm/internal/layer.js.map +1 -1
- package/dist/esm/internal/logger.js +25 -2
- package/dist/esm/internal/logger.js.map +1 -1
- package/dist/esm/internal/runtimeFlags.js +1 -9
- package/dist/esm/internal/runtimeFlags.js.map +1 -1
- package/dist/esm/internal/tracer.js +0 -111
- package/dist/esm/internal/tracer.js.map +1 -1
- package/package.json +12 -1
- package/src/Arbitrary.ts +1101 -0
- package/src/Array.ts +3589 -0
- package/src/BigDecimal.ts +1349 -0
- package/src/BigInt.ts +643 -0
- package/src/Boolean.ts +287 -0
- package/src/Brand.ts +360 -0
- package/src/Cache.ts +281 -0
- package/src/Cause.ts +1555 -0
- package/src/Channel.ts +2355 -0
- package/src/ChildExecutorDecision.ts +146 -0
- package/src/Chunk.ts +1495 -0
- package/src/Clock.ts +111 -0
- package/src/Config.ts +542 -0
- package/src/ConfigError.ts +270 -0
- package/src/ConfigProvider.ts +333 -0
- package/src/ConfigProviderPathPatch.ts +100 -0
- package/src/Console.ts +226 -0
- package/src/Context.ts +585 -0
- package/src/Cron.ts +706 -0
- package/src/Data.ts +596 -0
- package/src/DateTime.ts +1686 -0
- package/src/DefaultServices.ts +34 -0
- package/src/Deferred.ts +301 -0
- package/src/Differ.ts +450 -0
- package/src/Duration.ts +1000 -0
- package/src/Effect.ts +14817 -0
- package/src/Effectable.ts +107 -0
- package/src/Either.ts +1040 -0
- package/src/Encoding.ts +195 -0
- package/src/Equal.ts +98 -0
- package/src/Equivalence.ts +235 -0
- package/src/ExecutionPlan.ts +308 -0
- package/src/ExecutionStrategy.ts +119 -0
- package/src/Exit.ts +467 -0
- package/src/FastCheck.ts +9 -0
- package/src/Fiber.ts +744 -0
- package/src/FiberHandle.ts +540 -0
- package/src/FiberId.ts +195 -0
- package/src/FiberMap.ts +656 -0
- package/src/FiberRef.ts +444 -0
- package/src/FiberRefs.ts +204 -0
- package/src/FiberRefsPatch.ts +105 -0
- package/src/FiberSet.ts +491 -0
- package/src/FiberStatus.ts +108 -0
- package/src/Function.ts +1222 -0
- package/src/GlobalValue.ts +53 -0
- package/src/Graph.ts +3732 -0
- package/src/GroupBy.ts +103 -0
- package/src/HKT.ts +45 -0
- package/src/Hash.ts +195 -0
- package/src/HashMap.ts +519 -0
- package/src/HashRing.ts +317 -0
- package/src/HashSet.ts +2346 -0
- package/src/Inspectable.ts +287 -0
- package/src/Iterable.ts +1119 -0
- package/src/JSONSchema.ts +1044 -0
- package/src/KeyedPool.ts +167 -0
- package/src/Layer.ts +1228 -0
- package/src/LayerMap.ts +436 -0
- package/src/List.ts +977 -0
- package/src/LogLevel.ts +285 -0
- package/src/LogSpan.ts +25 -0
- package/src/Logger.ts +702 -0
- package/src/Mailbox.ts +268 -0
- package/src/ManagedRuntime.ts +180 -0
- package/src/Match.ts +1477 -0
- package/src/MergeDecision.ts +95 -0
- package/src/MergeState.ts +172 -0
- package/src/MergeStrategy.ts +107 -0
- package/src/Metric.ts +780 -0
- package/src/MetricBoundaries.ts +69 -0
- package/src/MetricHook.ts +151 -0
- package/src/MetricKey.ts +224 -0
- package/src/MetricKeyType.ts +262 -0
- package/src/MetricLabel.ts +47 -0
- package/src/MetricPair.ts +71 -0
- package/src/MetricPolling.ts +148 -0
- package/src/MetricRegistry.ts +48 -0
- package/src/MetricState.ts +257 -0
- package/src/Micro.ts +4405 -0
- package/src/ModuleVersion.ts +18 -0
- package/src/MutableHashMap.ts +411 -0
- package/src/MutableHashSet.ts +706 -0
- package/src/MutableList.ts +297 -0
- package/src/MutableQueue.ts +227 -0
- package/src/MutableRef.ts +202 -0
- package/src/NonEmptyIterable.ts +32 -0
- package/src/Number.ts +1071 -0
- package/src/Option.ts +2170 -0
- package/src/Order.ts +373 -0
- package/src/Ordering.ts +111 -0
- package/src/ParseResult.ts +2031 -0
- package/src/PartitionedSemaphore.ts +200 -0
- package/src/Pipeable.ts +566 -0
- package/src/Pool.ts +204 -0
- package/src/Predicate.ts +1405 -0
- package/src/Pretty.ts +205 -0
- package/src/PrimaryKey.ts +23 -0
- package/src/PubSub.ts +182 -0
- package/src/Queue.ts +644 -0
- package/src/Random.ts +204 -0
- package/src/RateLimiter.ts +138 -0
- package/src/RcMap.ts +141 -0
- package/src/RcRef.ts +122 -0
- package/src/Readable.ts +93 -0
- package/src/Record.ts +1274 -0
- package/src/RedBlackTree.ts +421 -0
- package/src/Redacted.ts +144 -0
- package/src/Ref.ts +180 -0
- package/src/RegExp.ts +38 -0
- package/src/Reloadable.ts +127 -0
- package/src/Request.ts +347 -0
- package/src/RequestBlock.ts +118 -0
- package/src/RequestResolver.ts +366 -0
- package/src/Resource.ts +119 -0
- package/src/Runtime.ts +383 -0
- package/src/RuntimeFlags.ts +336 -0
- package/src/RuntimeFlagsPatch.ts +183 -0
- package/src/STM.ts +2045 -0
- package/src/Schedule.ts +2219 -0
- package/src/ScheduleDecision.ts +62 -0
- package/src/ScheduleInterval.ts +151 -0
- package/src/ScheduleIntervals.ts +122 -0
- package/src/Scheduler.ts +353 -0
- package/src/Schema.ts +10914 -0
- package/src/SchemaAST.ts +3043 -0
- package/src/Scope.ts +204 -0
- package/src/ScopedCache.ts +151 -0
- package/src/ScopedRef.ts +117 -0
- package/src/Secret.ts +88 -0
- package/src/SingleProducerAsyncInput.ts +67 -0
- package/src/Sink.ts +1461 -0
- package/src/SortedMap.ts +287 -0
- package/src/SortedSet.ts +390 -0
- package/src/SourceLocation.ts +108 -0
- package/src/Stream.ts +6468 -0
- package/src/StreamEmit.ts +136 -0
- package/src/StreamHaltStrategy.ts +123 -0
- package/src/Streamable.ts +45 -0
- package/src/String.ts +778 -0
- package/src/Struct.ts +243 -0
- package/src/Subscribable.ts +100 -0
- package/src/SubscriptionRef.ts +298 -0
- package/src/Supervisor.ts +240 -0
- package/src/Symbol.ts +29 -0
- package/src/SynchronizedRef.ts +270 -0
- package/src/TArray.ts +495 -0
- package/src/TDeferred.ts +100 -0
- package/src/TMap.ts +515 -0
- package/src/TPriorityQueue.ts +223 -0
- package/src/TPubSub.ts +200 -0
- package/src/TQueue.ts +432 -0
- package/src/TRandom.ts +129 -0
- package/src/TReentrantLock.ts +224 -0
- package/src/TRef.ts +178 -0
- package/src/TSemaphore.ts +129 -0
- package/src/TSet.ts +365 -0
- package/src/TSubscriptionRef.ts +192 -0
- package/src/Take.ts +258 -0
- package/src/TestAnnotation.ts +158 -0
- package/src/TestAnnotationMap.ts +119 -0
- package/src/TestAnnotations.ts +117 -0
- package/src/TestClock.ts +556 -0
- package/src/TestConfig.ts +47 -0
- package/src/TestContext.ts +36 -0
- package/src/TestLive.ts +53 -0
- package/src/TestServices.ts +390 -0
- package/src/TestSized.ts +55 -0
- package/src/Tracer.ts +182 -0
- package/src/Trie.ts +840 -0
- package/src/Tuple.ts +305 -0
- package/src/Types.ts +353 -0
- package/src/Unify.ts +113 -0
- package/src/UpstreamPullRequest.ts +117 -0
- package/src/UpstreamPullStrategy.ts +121 -0
- package/src/Utils.ts +809 -0
- package/src/index.ts +1568 -0
- package/src/internal/array.ts +8 -0
- package/src/internal/blockedRequests.ts +520 -0
- package/src/internal/cache.ts +733 -0
- package/src/internal/cause.ts +1050 -0
- package/src/internal/channel/channelExecutor.ts +1200 -0
- package/src/internal/channel/channelState.ts +134 -0
- package/src/internal/channel/childExecutorDecision.ts +96 -0
- package/src/internal/channel/continuation.ts +200 -0
- package/src/internal/channel/mergeDecision.ts +113 -0
- package/src/internal/channel/mergeState.ts +120 -0
- package/src/internal/channel/mergeStrategy.ts +72 -0
- package/src/internal/channel/singleProducerAsyncInput.ts +259 -0
- package/src/internal/channel/subexecutor.ts +229 -0
- package/src/internal/channel/upstreamPullRequest.ts +84 -0
- package/src/internal/channel/upstreamPullStrategy.ts +87 -0
- package/src/internal/channel.ts +2603 -0
- package/src/internal/clock.ts +95 -0
- package/src/internal/completedRequestMap.ts +9 -0
- package/src/internal/concurrency.ts +54 -0
- package/src/internal/config.ts +716 -0
- package/src/internal/configError.ts +304 -0
- package/src/internal/configProvider/pathPatch.ts +97 -0
- package/src/internal/configProvider.ts +799 -0
- package/src/internal/console.ts +153 -0
- package/src/internal/context.ts +337 -0
- package/src/internal/core-effect.ts +2293 -0
- package/src/internal/core-stream.ts +998 -0
- package/src/internal/core.ts +3189 -0
- package/src/internal/data.ts +36 -0
- package/src/internal/dataSource.ts +327 -0
- package/src/internal/dateTime.ts +1277 -0
- package/src/internal/defaultServices/console.ts +100 -0
- package/src/internal/defaultServices.ts +163 -0
- package/src/internal/deferred.ts +46 -0
- package/src/internal/differ/chunkPatch.ts +211 -0
- package/src/internal/differ/contextPatch.ts +232 -0
- package/src/internal/differ/hashMapPatch.ts +220 -0
- package/src/internal/differ/hashSetPatch.ts +176 -0
- package/src/internal/differ/orPatch.ts +311 -0
- package/src/internal/differ/readonlyArrayPatch.ts +210 -0
- package/src/internal/differ.ts +200 -0
- package/src/internal/doNotation.ts +80 -0
- package/src/internal/effect/circular.ts +895 -0
- package/src/internal/effectable.ts +131 -0
- package/src/internal/either.ts +110 -0
- package/src/internal/encoding/base64.ts +286 -0
- package/src/internal/encoding/base64Url.ts +29 -0
- package/src/internal/encoding/common.ts +51 -0
- package/src/internal/encoding/hex.ts +315 -0
- package/src/internal/errors.ts +7 -0
- package/src/internal/executionPlan.ts +114 -0
- package/src/internal/executionStrategy.ts +74 -0
- package/src/internal/fiber.ts +388 -0
- package/src/internal/fiberId.ts +267 -0
- package/src/internal/fiberMessage.ts +82 -0
- package/src/internal/fiberRefs/patch.ts +144 -0
- package/src/internal/fiberRefs.ts +297 -0
- package/src/internal/fiberRuntime.ts +3842 -0
- package/src/internal/fiberScope.ts +71 -0
- package/src/internal/fiberStatus.ts +119 -0
- package/src/internal/groupBy.ts +530 -0
- package/src/internal/hashMap/array.ts +49 -0
- package/src/internal/hashMap/bitwise.ts +32 -0
- package/src/internal/hashMap/config.ts +14 -0
- package/src/internal/hashMap/keySet.ts +8 -0
- package/src/internal/hashMap/node.ts +391 -0
- package/src/internal/hashMap.ts +586 -0
- package/src/internal/hashSet.ts +323 -0
- package/src/internal/keyedPool.ts +244 -0
- package/src/internal/layer/circular.ts +214 -0
- package/src/internal/layer.ts +1483 -0
- package/src/internal/logSpan.ts +20 -0
- package/src/internal/logger-circular.ts +24 -0
- package/src/internal/logger.ts +522 -0
- package/src/internal/mailbox.ts +561 -0
- package/src/internal/managedRuntime/circular.ts +6 -0
- package/src/internal/managedRuntime.ts +134 -0
- package/src/internal/matcher.ts +652 -0
- package/src/internal/metric/boundaries.ts +75 -0
- package/src/internal/metric/hook.ts +483 -0
- package/src/internal/metric/key.ts +167 -0
- package/src/internal/metric/keyType.ts +238 -0
- package/src/internal/metric/label.ts +41 -0
- package/src/internal/metric/pair.ts +48 -0
- package/src/internal/metric/polling.ts +149 -0
- package/src/internal/metric/registry.ts +187 -0
- package/src/internal/metric/state.ts +290 -0
- package/src/internal/metric.ts +577 -0
- package/src/internal/opCodes/cause.ts +35 -0
- package/src/internal/opCodes/channel.ts +83 -0
- package/src/internal/opCodes/channelChildExecutorDecision.ts +17 -0
- package/src/internal/opCodes/channelMergeDecision.ts +11 -0
- package/src/internal/opCodes/channelMergeState.ts +17 -0
- package/src/internal/opCodes/channelMergeStrategy.ts +11 -0
- package/src/internal/opCodes/channelState.ts +23 -0
- package/src/internal/opCodes/channelUpstreamPullRequest.ts +11 -0
- package/src/internal/opCodes/channelUpstreamPullStrategy.ts +11 -0
- package/src/internal/opCodes/config.ts +65 -0
- package/src/internal/opCodes/configError.ts +35 -0
- package/src/internal/opCodes/continuation.ts +11 -0
- package/src/internal/opCodes/deferred.ts +11 -0
- package/src/internal/opCodes/effect.ts +89 -0
- package/src/internal/opCodes/layer.ts +59 -0
- package/src/internal/opCodes/streamHaltStrategy.ts +23 -0
- package/src/internal/option.ts +80 -0
- package/src/internal/pool.ts +432 -0
- package/src/internal/pubsub.ts +1762 -0
- package/src/internal/query.ts +204 -0
- package/src/internal/queue.ts +766 -0
- package/src/internal/random.ts +161 -0
- package/src/internal/rateLimiter.ts +93 -0
- package/src/internal/rcMap.ts +285 -0
- package/src/internal/rcRef.ts +192 -0
- package/src/internal/redBlackTree/iterator.ts +200 -0
- package/src/internal/redBlackTree/node.ts +68 -0
- package/src/internal/redBlackTree.ts +1245 -0
- package/src/internal/redacted.ts +73 -0
- package/src/internal/ref.ts +171 -0
- package/src/internal/reloadable.ts +140 -0
- package/src/internal/request.ts +177 -0
- package/src/internal/resource.ts +76 -0
- package/src/internal/ringBuffer.ts +68 -0
- package/src/internal/runtime.ts +558 -0
- package/src/internal/runtimeFlags.ts +178 -0
- package/src/internal/runtimeFlagsPatch.ts +103 -0
- package/src/internal/schedule/decision.ts +47 -0
- package/src/internal/schedule/interval.ts +101 -0
- package/src/internal/schedule/intervals.ts +180 -0
- package/src/internal/schedule.ts +2199 -0
- package/src/internal/schema/errors.ts +191 -0
- package/src/internal/schema/schemaId.ts +106 -0
- package/src/internal/schema/util.ts +50 -0
- package/src/internal/scopedCache.ts +644 -0
- package/src/internal/scopedRef.ts +118 -0
- package/src/internal/secret.ts +89 -0
- package/src/internal/singleShotGen.ts +35 -0
- package/src/internal/sink.ts +2120 -0
- package/src/internal/stack.ts +10 -0
- package/src/internal/stm/core.ts +817 -0
- package/src/internal/stm/entry.ts +59 -0
- package/src/internal/stm/journal.ts +123 -0
- package/src/internal/stm/opCodes/stm.ts +71 -0
- package/src/internal/stm/opCodes/stmState.ts +17 -0
- package/src/internal/stm/opCodes/strategy.ts +17 -0
- package/src/internal/stm/opCodes/tExit.ts +29 -0
- package/src/internal/stm/opCodes/tryCommit.ts +11 -0
- package/src/internal/stm/stm.ts +1453 -0
- package/src/internal/stm/stmState.ts +136 -0
- package/src/internal/stm/tArray.ts +550 -0
- package/src/internal/stm/tDeferred.ts +81 -0
- package/src/internal/stm/tExit.ts +190 -0
- package/src/internal/stm/tMap.ts +824 -0
- package/src/internal/stm/tPriorityQueue.ts +267 -0
- package/src/internal/stm/tPubSub.ts +551 -0
- package/src/internal/stm/tQueue.ts +393 -0
- package/src/internal/stm/tRandom.ts +140 -0
- package/src/internal/stm/tReentrantLock.ts +352 -0
- package/src/internal/stm/tRef.ts +195 -0
- package/src/internal/stm/tSemaphore.ts +113 -0
- package/src/internal/stm/tSet.ts +259 -0
- package/src/internal/stm/tSubscriptionRef.ts +286 -0
- package/src/internal/stm/tryCommit.ts +34 -0
- package/src/internal/stm/txnId.ts +14 -0
- package/src/internal/stm/versioned.ts +4 -0
- package/src/internal/stream/debounceState.ts +57 -0
- package/src/internal/stream/emit.ts +123 -0
- package/src/internal/stream/haltStrategy.ts +94 -0
- package/src/internal/stream/handoff.ts +187 -0
- package/src/internal/stream/handoffSignal.ts +59 -0
- package/src/internal/stream/pull.ts +34 -0
- package/src/internal/stream/sinkEndReason.ts +30 -0
- package/src/internal/stream/zipAllState.ts +88 -0
- package/src/internal/stream/zipChunksState.ts +56 -0
- package/src/internal/stream.ts +8801 -0
- package/src/internal/string-utils.ts +107 -0
- package/src/internal/subscriptionRef.ts +138 -0
- package/src/internal/supervisor/patch.ts +190 -0
- package/src/internal/supervisor.ts +303 -0
- package/src/internal/synchronizedRef.ts +114 -0
- package/src/internal/take.ts +199 -0
- package/src/internal/testing/sleep.ts +27 -0
- package/src/internal/testing/suspendedWarningData.ts +85 -0
- package/src/internal/testing/warningData.ts +94 -0
- package/src/internal/tracer.ts +150 -0
- package/src/internal/trie.ts +722 -0
- package/src/internal/version.ts +7 -0
|
@@ -0,0 +1,1349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This module provides utility functions and type class instances for working with the `BigDecimal` type in TypeScript.
|
|
3
|
+
* It includes functions for basic arithmetic operations, as well as type class instances for `Equivalence` and `Order`.
|
|
4
|
+
*
|
|
5
|
+
* A `BigDecimal` allows storing any real number to arbitrary precision; which avoids common floating point errors
|
|
6
|
+
* (such as 0.1 + 0.2 ≠ 0.3) at the cost of complexity.
|
|
7
|
+
*
|
|
8
|
+
* Internally, `BigDecimal` uses a `BigInt` object, paired with a 64-bit integer which determines the position of the
|
|
9
|
+
* decimal point. Therefore, the precision *is not* actually arbitrary, but limited to 2<sup>63</sup> decimal places.
|
|
10
|
+
*
|
|
11
|
+
* It is not recommended to convert a floating point number to a decimal directly, as the floating point representation
|
|
12
|
+
* may be unexpected.
|
|
13
|
+
*
|
|
14
|
+
* @module BigDecimal
|
|
15
|
+
* @since 2.0.0
|
|
16
|
+
* @see {@link module:BigInt} for more similar operations on `bigint` types
|
|
17
|
+
* @see {@link module:Number} for more similar operations on `number` types
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import * as Equal from "./Equal.js"
|
|
21
|
+
import * as equivalence from "./Equivalence.js"
|
|
22
|
+
import { dual, pipe } from "./Function.js"
|
|
23
|
+
import * as Hash from "./Hash.js"
|
|
24
|
+
import { type Inspectable, NodeInspectSymbol } from "./Inspectable.js"
|
|
25
|
+
import * as Option from "./Option.js"
|
|
26
|
+
import * as order from "./Order.js"
|
|
27
|
+
import type { Ordering } from "./Ordering.js"
|
|
28
|
+
import { type Pipeable, pipeArguments } from "./Pipeable.js"
|
|
29
|
+
import { hasProperty } from "./Predicate.js"
|
|
30
|
+
|
|
31
|
+
const DEFAULT_PRECISION = 100
|
|
32
|
+
const FINITE_INT_REGEX = /^[+-]?\d+$/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @since 2.0.0
|
|
36
|
+
* @category symbols
|
|
37
|
+
*/
|
|
38
|
+
export const TypeId: unique symbol = Symbol.for("effect/BigDecimal")
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @since 2.0.0
|
|
42
|
+
* @category symbol
|
|
43
|
+
*/
|
|
44
|
+
export type TypeId = typeof TypeId
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @since 2.0.0
|
|
48
|
+
* @category models
|
|
49
|
+
*/
|
|
50
|
+
export interface BigDecimal extends Equal.Equal, Pipeable, Inspectable {
|
|
51
|
+
readonly [TypeId]: TypeId
|
|
52
|
+
readonly value: bigint
|
|
53
|
+
readonly scale: number
|
|
54
|
+
/** @internal */
|
|
55
|
+
normalized?: BigDecimal
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const BigDecimalProto: Omit<BigDecimal, "value" | "scale" | "normalized"> = {
|
|
59
|
+
[TypeId]: TypeId,
|
|
60
|
+
[Hash.symbol](this: BigDecimal): number {
|
|
61
|
+
const normalized = normalize(this)
|
|
62
|
+
return pipe(
|
|
63
|
+
Hash.hash(normalized.value),
|
|
64
|
+
Hash.combine(Hash.number(normalized.scale)),
|
|
65
|
+
Hash.cached(this)
|
|
66
|
+
)
|
|
67
|
+
},
|
|
68
|
+
[Equal.symbol](this: BigDecimal, that: unknown): boolean {
|
|
69
|
+
return isBigDecimal(that) && equals(this, that)
|
|
70
|
+
},
|
|
71
|
+
toString(this: BigDecimal) {
|
|
72
|
+
return `BigDecimal(${format(this)})`
|
|
73
|
+
},
|
|
74
|
+
toJSON(this: BigDecimal) {
|
|
75
|
+
return {
|
|
76
|
+
_id: "BigDecimal",
|
|
77
|
+
value: String(this.value),
|
|
78
|
+
scale: this.scale
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
[NodeInspectSymbol](this: BigDecimal) {
|
|
82
|
+
return this.toJSON()
|
|
83
|
+
},
|
|
84
|
+
pipe() {
|
|
85
|
+
return pipeArguments(this, arguments)
|
|
86
|
+
}
|
|
87
|
+
} as const
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Checks if a given value is a `BigDecimal`.
|
|
91
|
+
*
|
|
92
|
+
* @since 2.0.0
|
|
93
|
+
* @category guards
|
|
94
|
+
*/
|
|
95
|
+
export const isBigDecimal = (u: unknown): u is BigDecimal => hasProperty(u, TypeId)
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Creates a `BigDecimal` from a `bigint` value and a scale.
|
|
99
|
+
*
|
|
100
|
+
* @since 2.0.0
|
|
101
|
+
* @category constructors
|
|
102
|
+
*/
|
|
103
|
+
export const make = (value: bigint, scale: number): BigDecimal => {
|
|
104
|
+
const o = Object.create(BigDecimalProto)
|
|
105
|
+
o.value = value
|
|
106
|
+
o.scale = scale
|
|
107
|
+
return o
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Internal function used to create pre-normalized `BigDecimal`s.
|
|
112
|
+
*
|
|
113
|
+
* @internal
|
|
114
|
+
*/
|
|
115
|
+
export const unsafeMakeNormalized = (value: bigint, scale: number): BigDecimal => {
|
|
116
|
+
if (value !== bigint0 && value % bigint10 === bigint0) {
|
|
117
|
+
throw new RangeError("Value must be normalized")
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const o = make(value, scale)
|
|
121
|
+
o.normalized = o
|
|
122
|
+
return o
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const bigint0 = BigInt(0)
|
|
126
|
+
const bigint1 = BigInt(1)
|
|
127
|
+
const bigint10 = BigInt(10)
|
|
128
|
+
const zero = unsafeMakeNormalized(bigint0, 0)
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Normalizes a given `BigDecimal` by removing trailing zeros.
|
|
132
|
+
*
|
|
133
|
+
* **Example**
|
|
134
|
+
*
|
|
135
|
+
* ```ts
|
|
136
|
+
* import * as assert from "node:assert"
|
|
137
|
+
* import { normalize, make, unsafeFromString } from "effect/BigDecimal"
|
|
138
|
+
*
|
|
139
|
+
* assert.deepStrictEqual(normalize(unsafeFromString("123.00000")), normalize(make(123n, 0)))
|
|
140
|
+
* assert.deepStrictEqual(normalize(unsafeFromString("12300000")), normalize(make(123n, -5)))
|
|
141
|
+
* ```
|
|
142
|
+
*
|
|
143
|
+
* @since 2.0.0
|
|
144
|
+
* @category scaling
|
|
145
|
+
*/
|
|
146
|
+
export const normalize = (self: BigDecimal): BigDecimal => {
|
|
147
|
+
if (self.normalized === undefined) {
|
|
148
|
+
if (self.value === bigint0) {
|
|
149
|
+
self.normalized = zero
|
|
150
|
+
} else {
|
|
151
|
+
const digits = `${self.value}`
|
|
152
|
+
|
|
153
|
+
let trail = 0
|
|
154
|
+
for (let i = digits.length - 1; i >= 0; i--) {
|
|
155
|
+
if (digits[i] === "0") {
|
|
156
|
+
trail++
|
|
157
|
+
} else {
|
|
158
|
+
break
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (trail === 0) {
|
|
163
|
+
self.normalized = self
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const value = BigInt(digits.substring(0, digits.length - trail))
|
|
167
|
+
const scale = self.scale - trail
|
|
168
|
+
self.normalized = unsafeMakeNormalized(value, scale)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return self.normalized
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Scales a given `BigDecimal` to the specified scale.
|
|
177
|
+
*
|
|
178
|
+
* If the given scale is smaller than the current scale, the value will be rounded down to
|
|
179
|
+
* the nearest integer.
|
|
180
|
+
*
|
|
181
|
+
* @since 2.0.0
|
|
182
|
+
* @category scaling
|
|
183
|
+
*/
|
|
184
|
+
export const scale: {
|
|
185
|
+
(scale: number): (self: BigDecimal) => BigDecimal
|
|
186
|
+
(self: BigDecimal, scale: number): BigDecimal
|
|
187
|
+
} = dual(2, (self: BigDecimal, scale: number): BigDecimal => {
|
|
188
|
+
if (scale > self.scale) {
|
|
189
|
+
return make(self.value * bigint10 ** BigInt(scale - self.scale), scale)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (scale < self.scale) {
|
|
193
|
+
return make(self.value / bigint10 ** BigInt(self.scale - scale), scale)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return self
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Provides an addition operation on `BigDecimal`s.
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```ts
|
|
204
|
+
* import * as assert from "node:assert"
|
|
205
|
+
* import { sum, unsafeFromString } from "effect/BigDecimal"
|
|
206
|
+
*
|
|
207
|
+
* assert.deepStrictEqual(sum(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("5"))
|
|
208
|
+
* ```
|
|
209
|
+
*
|
|
210
|
+
* @since 2.0.0
|
|
211
|
+
* @category math
|
|
212
|
+
*/
|
|
213
|
+
export const sum: {
|
|
214
|
+
(that: BigDecimal): (self: BigDecimal) => BigDecimal
|
|
215
|
+
(self: BigDecimal, that: BigDecimal): BigDecimal
|
|
216
|
+
} = dual(2, (self: BigDecimal, that: BigDecimal): BigDecimal => {
|
|
217
|
+
if (that.value === bigint0) {
|
|
218
|
+
return self
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (self.value === bigint0) {
|
|
222
|
+
return that
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (self.scale > that.scale) {
|
|
226
|
+
return make(scale(that, self.scale).value + self.value, self.scale)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (self.scale < that.scale) {
|
|
230
|
+
return make(scale(self, that.scale).value + that.value, that.scale)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return make(self.value + that.value, self.scale)
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Provides a multiplication operation on `BigDecimal`s.
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ```ts
|
|
241
|
+
* import * as assert from "node:assert"
|
|
242
|
+
* import { multiply, unsafeFromString } from "effect/BigDecimal"
|
|
243
|
+
*
|
|
244
|
+
* assert.deepStrictEqual(multiply(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("6"))
|
|
245
|
+
* ```
|
|
246
|
+
*
|
|
247
|
+
* @since 2.0.0
|
|
248
|
+
* @category math
|
|
249
|
+
*/
|
|
250
|
+
export const multiply: {
|
|
251
|
+
(that: BigDecimal): (self: BigDecimal) => BigDecimal
|
|
252
|
+
(self: BigDecimal, that: BigDecimal): BigDecimal
|
|
253
|
+
} = dual(2, (self: BigDecimal, that: BigDecimal): BigDecimal => {
|
|
254
|
+
if (that.value === bigint0 || self.value === bigint0) {
|
|
255
|
+
return zero
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return make(self.value * that.value, self.scale + that.scale)
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Provides a subtraction operation on `BigDecimal`s.
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* ```ts
|
|
266
|
+
* import * as assert from "node:assert"
|
|
267
|
+
* import { subtract, unsafeFromString } from "effect/BigDecimal"
|
|
268
|
+
*
|
|
269
|
+
* assert.deepStrictEqual(subtract(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("-1"))
|
|
270
|
+
* ```
|
|
271
|
+
*
|
|
272
|
+
* @since 2.0.0
|
|
273
|
+
* @category math
|
|
274
|
+
*/
|
|
275
|
+
export const subtract: {
|
|
276
|
+
(that: BigDecimal): (self: BigDecimal) => BigDecimal
|
|
277
|
+
(self: BigDecimal, that: BigDecimal): BigDecimal
|
|
278
|
+
} = dual(2, (self: BigDecimal, that: BigDecimal): BigDecimal => {
|
|
279
|
+
if (that.value === bigint0) {
|
|
280
|
+
return self
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (self.value === bigint0) {
|
|
284
|
+
return make(-that.value, that.scale)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (self.scale > that.scale) {
|
|
288
|
+
return make(self.value - scale(that, self.scale).value, self.scale)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (self.scale < that.scale) {
|
|
292
|
+
return make(scale(self, that.scale).value - that.value, that.scale)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return make(self.value - that.value, self.scale)
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Internal function used for arbitrary precision division.
|
|
300
|
+
*/
|
|
301
|
+
const divideWithPrecision = (
|
|
302
|
+
num: bigint,
|
|
303
|
+
den: bigint,
|
|
304
|
+
scale: number,
|
|
305
|
+
precision: number
|
|
306
|
+
): BigDecimal => {
|
|
307
|
+
const numNegative = num < bigint0
|
|
308
|
+
const denNegative = den < bigint0
|
|
309
|
+
const negateResult = numNegative !== denNegative
|
|
310
|
+
|
|
311
|
+
num = numNegative ? -num : num
|
|
312
|
+
den = denNegative ? -den : den
|
|
313
|
+
|
|
314
|
+
// Shift digits until numerator is larger than denominator (set scale appropriately).
|
|
315
|
+
while (num < den) {
|
|
316
|
+
num *= bigint10
|
|
317
|
+
scale++
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// First division.
|
|
321
|
+
let quotient = num / den
|
|
322
|
+
let remainder = num % den
|
|
323
|
+
|
|
324
|
+
if (remainder === bigint0) {
|
|
325
|
+
// No remainder, return immediately.
|
|
326
|
+
return make(negateResult ? -quotient : quotient, scale)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// The quotient is guaranteed to be non-negative at this point. No need to consider sign.
|
|
330
|
+
let count = `${quotient}`.length
|
|
331
|
+
|
|
332
|
+
// Shift the remainder by 1 decimal; The quotient will be 1 digit upon next division.
|
|
333
|
+
remainder *= bigint10
|
|
334
|
+
while (remainder !== bigint0 && count < precision) {
|
|
335
|
+
const q = remainder / den
|
|
336
|
+
const r = remainder % den
|
|
337
|
+
quotient = quotient * bigint10 + q
|
|
338
|
+
remainder = r * bigint10
|
|
339
|
+
|
|
340
|
+
count++
|
|
341
|
+
scale++
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (remainder !== bigint0) {
|
|
345
|
+
// Round final number with remainder.
|
|
346
|
+
quotient += roundTerminal(remainder / den)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return make(negateResult ? -quotient : quotient, scale)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Internal function used for rounding.
|
|
354
|
+
*
|
|
355
|
+
* Returns 1 if the most significant digit is >= 5, otherwise 0.
|
|
356
|
+
*
|
|
357
|
+
* This is used after dividing a number by a power of ten and rounding the last digit.
|
|
358
|
+
*
|
|
359
|
+
* @internal
|
|
360
|
+
*/
|
|
361
|
+
export const roundTerminal = (n: bigint): bigint => {
|
|
362
|
+
const pos = n >= bigint0 ? 0 : 1
|
|
363
|
+
return Number(`${n}`[pos]) < 5 ? bigint0 : bigint1
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Provides a division operation on `BigDecimal`s.
|
|
368
|
+
*
|
|
369
|
+
* If the dividend is not a multiple of the divisor the result will be a `BigDecimal` value
|
|
370
|
+
* which represents the integer division rounded down to the nearest integer.
|
|
371
|
+
*
|
|
372
|
+
* If the divisor is `0`, the result will be `None`.
|
|
373
|
+
*
|
|
374
|
+
* @example
|
|
375
|
+
* ```ts
|
|
376
|
+
* import * as assert from "node:assert"
|
|
377
|
+
* import { BigDecimal, Option } from "effect"
|
|
378
|
+
*
|
|
379
|
+
* assert.deepStrictEqual(BigDecimal.divide(BigDecimal.unsafeFromString("6"), BigDecimal.unsafeFromString("3")), Option.some(BigDecimal.unsafeFromString("2")))
|
|
380
|
+
* assert.deepStrictEqual(BigDecimal.divide(BigDecimal.unsafeFromString("6"), BigDecimal.unsafeFromString("4")), Option.some(BigDecimal.unsafeFromString("1.5")))
|
|
381
|
+
* assert.deepStrictEqual(BigDecimal.divide(BigDecimal.unsafeFromString("6"), BigDecimal.unsafeFromString("0")), Option.none())
|
|
382
|
+
* ```
|
|
383
|
+
*
|
|
384
|
+
* @since 2.0.0
|
|
385
|
+
* @category math
|
|
386
|
+
*/
|
|
387
|
+
export const divide: {
|
|
388
|
+
(that: BigDecimal): (self: BigDecimal) => Option.Option<BigDecimal>
|
|
389
|
+
(self: BigDecimal, that: BigDecimal): Option.Option<BigDecimal>
|
|
390
|
+
} = dual(2, (self: BigDecimal, that: BigDecimal): Option.Option<BigDecimal> => {
|
|
391
|
+
if (that.value === bigint0) {
|
|
392
|
+
return Option.none()
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (self.value === bigint0) {
|
|
396
|
+
return Option.some(zero)
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const scale = self.scale - that.scale
|
|
400
|
+
if (self.value === that.value) {
|
|
401
|
+
return Option.some(make(bigint1, scale))
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return Option.some(divideWithPrecision(self.value, that.value, scale, DEFAULT_PRECISION))
|
|
405
|
+
})
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Provides an unsafe division operation on `BigDecimal`s.
|
|
409
|
+
*
|
|
410
|
+
* If the dividend is not a multiple of the divisor the result will be a `BigDecimal` value
|
|
411
|
+
* which represents the integer division rounded down to the nearest integer.
|
|
412
|
+
*
|
|
413
|
+
* Throws a `RangeError` if the divisor is `0`.
|
|
414
|
+
*
|
|
415
|
+
* @example
|
|
416
|
+
* ```ts
|
|
417
|
+
* import * as assert from "node:assert"
|
|
418
|
+
* import { unsafeDivide, unsafeFromString } from "effect/BigDecimal"
|
|
419
|
+
*
|
|
420
|
+
* assert.deepStrictEqual(unsafeDivide(unsafeFromString("6"), unsafeFromString("3")), unsafeFromString("2"))
|
|
421
|
+
* assert.deepStrictEqual(unsafeDivide(unsafeFromString("6"), unsafeFromString("4")), unsafeFromString("1.5"))
|
|
422
|
+
* ```
|
|
423
|
+
*
|
|
424
|
+
* @since 2.0.0
|
|
425
|
+
* @category math
|
|
426
|
+
*/
|
|
427
|
+
export const unsafeDivide: {
|
|
428
|
+
(that: BigDecimal): (self: BigDecimal) => BigDecimal
|
|
429
|
+
(self: BigDecimal, that: BigDecimal): BigDecimal
|
|
430
|
+
} = dual(2, (self: BigDecimal, that: BigDecimal): BigDecimal => {
|
|
431
|
+
if (that.value === bigint0) {
|
|
432
|
+
throw new RangeError("Division by zero")
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (self.value === bigint0) {
|
|
436
|
+
return zero
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const scale = self.scale - that.scale
|
|
440
|
+
if (self.value === that.value) {
|
|
441
|
+
return make(bigint1, scale)
|
|
442
|
+
}
|
|
443
|
+
return divideWithPrecision(self.value, that.value, scale, DEFAULT_PRECISION)
|
|
444
|
+
})
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* @since 2.0.0
|
|
448
|
+
* @category instances
|
|
449
|
+
*/
|
|
450
|
+
export const Order: order.Order<BigDecimal> = order.make((self, that) => {
|
|
451
|
+
const scmp = order.number(sign(self), sign(that))
|
|
452
|
+
if (scmp !== 0) {
|
|
453
|
+
return scmp
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (self.scale > that.scale) {
|
|
457
|
+
return order.bigint(self.value, scale(that, self.scale).value)
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (self.scale < that.scale) {
|
|
461
|
+
return order.bigint(scale(self, that.scale).value, that.value)
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return order.bigint(self.value, that.value)
|
|
465
|
+
})
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Returns `true` if the first argument is less than the second, otherwise `false`.
|
|
469
|
+
*
|
|
470
|
+
* @example
|
|
471
|
+
* ```ts
|
|
472
|
+
* import * as assert from "node:assert"
|
|
473
|
+
* import { lessThan, unsafeFromString } from "effect/BigDecimal"
|
|
474
|
+
*
|
|
475
|
+
* assert.deepStrictEqual(lessThan(unsafeFromString("2"), unsafeFromString("3")), true)
|
|
476
|
+
* assert.deepStrictEqual(lessThan(unsafeFromString("3"), unsafeFromString("3")), false)
|
|
477
|
+
* assert.deepStrictEqual(lessThan(unsafeFromString("4"), unsafeFromString("3")), false)
|
|
478
|
+
* ```
|
|
479
|
+
*
|
|
480
|
+
* @since 2.0.0
|
|
481
|
+
* @category predicates
|
|
482
|
+
*/
|
|
483
|
+
export const lessThan: {
|
|
484
|
+
(that: BigDecimal): (self: BigDecimal) => boolean
|
|
485
|
+
(self: BigDecimal, that: BigDecimal): boolean
|
|
486
|
+
} = order.lessThan(Order)
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Checks if a given `BigDecimal` is less than or equal to the provided one.
|
|
490
|
+
*
|
|
491
|
+
* @example
|
|
492
|
+
* ```ts
|
|
493
|
+
* import * as assert from "node:assert"
|
|
494
|
+
* import { lessThanOrEqualTo, unsafeFromString } from "effect/BigDecimal"
|
|
495
|
+
*
|
|
496
|
+
* assert.deepStrictEqual(lessThanOrEqualTo(unsafeFromString("2"), unsafeFromString("3")), true)
|
|
497
|
+
* assert.deepStrictEqual(lessThanOrEqualTo(unsafeFromString("3"), unsafeFromString("3")), true)
|
|
498
|
+
* assert.deepStrictEqual(lessThanOrEqualTo(unsafeFromString("4"), unsafeFromString("3")), false)
|
|
499
|
+
* ```
|
|
500
|
+
*
|
|
501
|
+
* @since 2.0.0
|
|
502
|
+
* @category predicates
|
|
503
|
+
*/
|
|
504
|
+
export const lessThanOrEqualTo: {
|
|
505
|
+
(that: BigDecimal): (self: BigDecimal) => boolean
|
|
506
|
+
(self: BigDecimal, that: BigDecimal): boolean
|
|
507
|
+
} = order.lessThanOrEqualTo(Order)
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Returns `true` if the first argument is greater than the second, otherwise `false`.
|
|
511
|
+
*
|
|
512
|
+
* @example
|
|
513
|
+
* ```ts
|
|
514
|
+
* import * as assert from "node:assert"
|
|
515
|
+
* import { greaterThan, unsafeFromString } from "effect/BigDecimal"
|
|
516
|
+
*
|
|
517
|
+
* assert.deepStrictEqual(greaterThan(unsafeFromString("2"), unsafeFromString("3")), false)
|
|
518
|
+
* assert.deepStrictEqual(greaterThan(unsafeFromString("3"), unsafeFromString("3")), false)
|
|
519
|
+
* assert.deepStrictEqual(greaterThan(unsafeFromString("4"), unsafeFromString("3")), true)
|
|
520
|
+
* ```
|
|
521
|
+
*
|
|
522
|
+
* @since 2.0.0
|
|
523
|
+
* @category predicates
|
|
524
|
+
*/
|
|
525
|
+
export const greaterThan: {
|
|
526
|
+
(that: BigDecimal): (self: BigDecimal) => boolean
|
|
527
|
+
(self: BigDecimal, that: BigDecimal): boolean
|
|
528
|
+
} = order.greaterThan(Order)
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Checks if a given `BigDecimal` is greater than or equal to the provided one.
|
|
532
|
+
*
|
|
533
|
+
* @example
|
|
534
|
+
* ```ts
|
|
535
|
+
* import * as assert from "node:assert"
|
|
536
|
+
* import { greaterThanOrEqualTo, unsafeFromString } from "effect/BigDecimal"
|
|
537
|
+
*
|
|
538
|
+
* assert.deepStrictEqual(greaterThanOrEqualTo(unsafeFromString("2"), unsafeFromString("3")), false)
|
|
539
|
+
* assert.deepStrictEqual(greaterThanOrEqualTo(unsafeFromString("3"), unsafeFromString("3")), true)
|
|
540
|
+
* assert.deepStrictEqual(greaterThanOrEqualTo(unsafeFromString("4"), unsafeFromString("3")), true)
|
|
541
|
+
* ```
|
|
542
|
+
*
|
|
543
|
+
* @since 2.0.0
|
|
544
|
+
* @category predicates
|
|
545
|
+
*/
|
|
546
|
+
export const greaterThanOrEqualTo: {
|
|
547
|
+
(that: BigDecimal): (self: BigDecimal) => boolean
|
|
548
|
+
(self: BigDecimal, that: BigDecimal): boolean
|
|
549
|
+
} = order.greaterThanOrEqualTo(Order)
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Checks if a `BigDecimal` is between a `minimum` and `maximum` value (inclusive).
|
|
553
|
+
*
|
|
554
|
+
* @example
|
|
555
|
+
* ```ts
|
|
556
|
+
* import * as assert from "node:assert"
|
|
557
|
+
* import { BigDecimal } from "effect"
|
|
558
|
+
*
|
|
559
|
+
* const between = BigDecimal.between({
|
|
560
|
+
* minimum: BigDecimal.unsafeFromString("1"),
|
|
561
|
+
* maximum: BigDecimal.unsafeFromString("5") }
|
|
562
|
+
* )
|
|
563
|
+
*
|
|
564
|
+
* assert.deepStrictEqual(between(BigDecimal.unsafeFromString("3")), true)
|
|
565
|
+
* assert.deepStrictEqual(between(BigDecimal.unsafeFromString("0")), false)
|
|
566
|
+
* assert.deepStrictEqual(between(BigDecimal.unsafeFromString("6")), false)
|
|
567
|
+
* ```
|
|
568
|
+
*
|
|
569
|
+
* @since 2.0.0
|
|
570
|
+
* @category predicates
|
|
571
|
+
*/
|
|
572
|
+
export const between: {
|
|
573
|
+
(options: {
|
|
574
|
+
minimum: BigDecimal
|
|
575
|
+
maximum: BigDecimal
|
|
576
|
+
}): (self: BigDecimal) => boolean
|
|
577
|
+
(self: BigDecimal, options: {
|
|
578
|
+
minimum: BigDecimal
|
|
579
|
+
maximum: BigDecimal
|
|
580
|
+
}): boolean
|
|
581
|
+
} = order.between(Order)
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Restricts the given `BigDecimal` to be within the range specified by the `minimum` and `maximum` values.
|
|
585
|
+
*
|
|
586
|
+
* - If the `BigDecimal` is less than the `minimum` value, the function returns the `minimum` value.
|
|
587
|
+
* - If the `BigDecimal` is greater than the `maximum` value, the function returns the `maximum` value.
|
|
588
|
+
* - Otherwise, it returns the original `BigDecimal`.
|
|
589
|
+
*
|
|
590
|
+
* @example
|
|
591
|
+
* ```ts
|
|
592
|
+
* import * as assert from "node:assert"
|
|
593
|
+
* import { BigDecimal } from "effect"
|
|
594
|
+
*
|
|
595
|
+
* const clamp = BigDecimal.clamp({
|
|
596
|
+
* minimum: BigDecimal.unsafeFromString("1"),
|
|
597
|
+
* maximum: BigDecimal.unsafeFromString("5") }
|
|
598
|
+
* )
|
|
599
|
+
*
|
|
600
|
+
* assert.deepStrictEqual(clamp(BigDecimal.unsafeFromString("3")), BigDecimal.unsafeFromString("3"))
|
|
601
|
+
* assert.deepStrictEqual(clamp(BigDecimal.unsafeFromString("0")), BigDecimal.unsafeFromString("1"))
|
|
602
|
+
* assert.deepStrictEqual(clamp(BigDecimal.unsafeFromString("6")), BigDecimal.unsafeFromString("5"))
|
|
603
|
+
* ```
|
|
604
|
+
*
|
|
605
|
+
* @since 2.0.0
|
|
606
|
+
* @category math
|
|
607
|
+
*/
|
|
608
|
+
export const clamp: {
|
|
609
|
+
(options: {
|
|
610
|
+
minimum: BigDecimal
|
|
611
|
+
maximum: BigDecimal
|
|
612
|
+
}): (self: BigDecimal) => BigDecimal
|
|
613
|
+
(self: BigDecimal, options: {
|
|
614
|
+
minimum: BigDecimal
|
|
615
|
+
maximum: BigDecimal
|
|
616
|
+
}): BigDecimal
|
|
617
|
+
} = order.clamp(Order)
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Returns the minimum between two `BigDecimal`s.
|
|
621
|
+
*
|
|
622
|
+
* @example
|
|
623
|
+
* ```ts
|
|
624
|
+
* import * as assert from "node:assert"
|
|
625
|
+
* import { min, unsafeFromString } from "effect/BigDecimal"
|
|
626
|
+
*
|
|
627
|
+
* assert.deepStrictEqual(min(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("2"))
|
|
628
|
+
* ```
|
|
629
|
+
*
|
|
630
|
+
* @since 2.0.0
|
|
631
|
+
* @category math
|
|
632
|
+
*/
|
|
633
|
+
export const min: {
|
|
634
|
+
(that: BigDecimal): (self: BigDecimal) => BigDecimal
|
|
635
|
+
(self: BigDecimal, that: BigDecimal): BigDecimal
|
|
636
|
+
} = order.min(Order)
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Returns the maximum between two `BigDecimal`s.
|
|
640
|
+
*
|
|
641
|
+
* @example
|
|
642
|
+
* ```ts
|
|
643
|
+
* import * as assert from "node:assert"
|
|
644
|
+
* import { max, unsafeFromString } from "effect/BigDecimal"
|
|
645
|
+
*
|
|
646
|
+
* assert.deepStrictEqual(max(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("3"))
|
|
647
|
+
* ```
|
|
648
|
+
*
|
|
649
|
+
* @since 2.0.0
|
|
650
|
+
* @category math
|
|
651
|
+
*/
|
|
652
|
+
export const max: {
|
|
653
|
+
(that: BigDecimal): (self: BigDecimal) => BigDecimal
|
|
654
|
+
(self: BigDecimal, that: BigDecimal): BigDecimal
|
|
655
|
+
} = order.max(Order)
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Determines the sign of a given `BigDecimal`.
|
|
659
|
+
*
|
|
660
|
+
* @example
|
|
661
|
+
* ```ts
|
|
662
|
+
* import * as assert from "node:assert"
|
|
663
|
+
* import { sign, unsafeFromString } from "effect/BigDecimal"
|
|
664
|
+
*
|
|
665
|
+
* assert.deepStrictEqual(sign(unsafeFromString("-5")), -1)
|
|
666
|
+
* assert.deepStrictEqual(sign(unsafeFromString("0")), 0)
|
|
667
|
+
* assert.deepStrictEqual(sign(unsafeFromString("5")), 1)
|
|
668
|
+
* ```
|
|
669
|
+
*
|
|
670
|
+
* @since 2.0.0
|
|
671
|
+
* @category math
|
|
672
|
+
*/
|
|
673
|
+
export const sign = (n: BigDecimal): Ordering => n.value === bigint0 ? 0 : n.value < bigint0 ? -1 : 1
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Determines the absolute value of a given `BigDecimal`.
|
|
677
|
+
*
|
|
678
|
+
* @example
|
|
679
|
+
* ```ts
|
|
680
|
+
* import * as assert from "node:assert"
|
|
681
|
+
* import { abs, unsafeFromString } from "effect/BigDecimal"
|
|
682
|
+
*
|
|
683
|
+
* assert.deepStrictEqual(abs(unsafeFromString("-5")), unsafeFromString("5"))
|
|
684
|
+
* assert.deepStrictEqual(abs(unsafeFromString("0")), unsafeFromString("0"))
|
|
685
|
+
* assert.deepStrictEqual(abs(unsafeFromString("5")), unsafeFromString("5"))
|
|
686
|
+
* ```
|
|
687
|
+
*
|
|
688
|
+
* @since 2.0.0
|
|
689
|
+
* @category math
|
|
690
|
+
*/
|
|
691
|
+
export const abs = (n: BigDecimal): BigDecimal => n.value < bigint0 ? make(-n.value, n.scale) : n
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* Provides a negate operation on `BigDecimal`s.
|
|
695
|
+
*
|
|
696
|
+
* @example
|
|
697
|
+
* ```ts
|
|
698
|
+
* import * as assert from "node:assert"
|
|
699
|
+
* import { negate, unsafeFromString } from "effect/BigDecimal"
|
|
700
|
+
*
|
|
701
|
+
* assert.deepStrictEqual(negate(unsafeFromString("3")), unsafeFromString("-3"))
|
|
702
|
+
* assert.deepStrictEqual(negate(unsafeFromString("-6")), unsafeFromString("6"))
|
|
703
|
+
* ```
|
|
704
|
+
*
|
|
705
|
+
* @since 2.0.0
|
|
706
|
+
* @category math
|
|
707
|
+
*/
|
|
708
|
+
export const negate = (n: BigDecimal): BigDecimal => make(-n.value, n.scale)
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* Returns the remainder left over when one operand is divided by a second operand.
|
|
712
|
+
*
|
|
713
|
+
* If the divisor is `0`, the result will be `None`.
|
|
714
|
+
*
|
|
715
|
+
* @example
|
|
716
|
+
* ```ts
|
|
717
|
+
* import * as assert from "node:assert"
|
|
718
|
+
* import { BigDecimal, Option } from "effect"
|
|
719
|
+
*
|
|
720
|
+
* assert.deepStrictEqual(BigDecimal.remainder(BigDecimal.unsafeFromString("2"), BigDecimal.unsafeFromString("2")), Option.some(BigDecimal.unsafeFromString("0")))
|
|
721
|
+
* assert.deepStrictEqual(BigDecimal.remainder(BigDecimal.unsafeFromString("3"), BigDecimal.unsafeFromString("2")), Option.some(BigDecimal.unsafeFromString("1")))
|
|
722
|
+
* assert.deepStrictEqual(BigDecimal.remainder(BigDecimal.unsafeFromString("-4"), BigDecimal.unsafeFromString("2")), Option.some(BigDecimal.unsafeFromString("0")))
|
|
723
|
+
* ```
|
|
724
|
+
*
|
|
725
|
+
* @since 2.0.0
|
|
726
|
+
* @category math
|
|
727
|
+
*/
|
|
728
|
+
export const remainder: {
|
|
729
|
+
(divisor: BigDecimal): (self: BigDecimal) => Option.Option<BigDecimal>
|
|
730
|
+
(self: BigDecimal, divisor: BigDecimal): Option.Option<BigDecimal>
|
|
731
|
+
} = dual(2, (self: BigDecimal, divisor: BigDecimal): Option.Option<BigDecimal> => {
|
|
732
|
+
if (divisor.value === bigint0) {
|
|
733
|
+
return Option.none()
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
const max = Math.max(self.scale, divisor.scale)
|
|
737
|
+
return Option.some(make(scale(self, max).value % scale(divisor, max).value, max))
|
|
738
|
+
})
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* Returns the remainder left over when one operand is divided by a second operand.
|
|
742
|
+
*
|
|
743
|
+
* Throws a `RangeError` if the divisor is `0`.
|
|
744
|
+
*
|
|
745
|
+
* @example
|
|
746
|
+
* ```ts
|
|
747
|
+
* import * as assert from "node:assert"
|
|
748
|
+
* import { unsafeRemainder, unsafeFromString } from "effect/BigDecimal"
|
|
749
|
+
*
|
|
750
|
+
* assert.deepStrictEqual(unsafeRemainder(unsafeFromString("2"), unsafeFromString("2")), unsafeFromString("0"))
|
|
751
|
+
* assert.deepStrictEqual(unsafeRemainder(unsafeFromString("3"), unsafeFromString("2")), unsafeFromString("1"))
|
|
752
|
+
* assert.deepStrictEqual(unsafeRemainder(unsafeFromString("-4"), unsafeFromString("2")), unsafeFromString("0"))
|
|
753
|
+
* ```
|
|
754
|
+
*
|
|
755
|
+
* @since 2.0.0
|
|
756
|
+
* @category math
|
|
757
|
+
*/
|
|
758
|
+
export const unsafeRemainder: {
|
|
759
|
+
(divisor: BigDecimal): (self: BigDecimal) => BigDecimal
|
|
760
|
+
(self: BigDecimal, divisor: BigDecimal): BigDecimal
|
|
761
|
+
} = dual(2, (self: BigDecimal, divisor: BigDecimal): BigDecimal => {
|
|
762
|
+
if (divisor.value === bigint0) {
|
|
763
|
+
throw new RangeError("Division by zero")
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
const max = Math.max(self.scale, divisor.scale)
|
|
767
|
+
return make(scale(self, max).value % scale(divisor, max).value, max)
|
|
768
|
+
})
|
|
769
|
+
|
|
770
|
+
/**
|
|
771
|
+
* @category instances
|
|
772
|
+
* @since 2.0.0
|
|
773
|
+
*/
|
|
774
|
+
export const Equivalence: equivalence.Equivalence<BigDecimal> = equivalence.make((self, that) => {
|
|
775
|
+
if (self.scale > that.scale) {
|
|
776
|
+
return scale(that, self.scale).value === self.value
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
if (self.scale < that.scale) {
|
|
780
|
+
return scale(self, that.scale).value === that.value
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
return self.value === that.value
|
|
784
|
+
})
|
|
785
|
+
|
|
786
|
+
/**
|
|
787
|
+
* Checks if two `BigDecimal`s are equal.
|
|
788
|
+
*
|
|
789
|
+
* @since 2.0.0
|
|
790
|
+
* @category predicates
|
|
791
|
+
*/
|
|
792
|
+
export const equals: {
|
|
793
|
+
(that: BigDecimal): (self: BigDecimal) => boolean
|
|
794
|
+
(self: BigDecimal, that: BigDecimal): boolean
|
|
795
|
+
} = dual(2, (self: BigDecimal, that: BigDecimal): boolean => Equivalence(self, that))
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* Creates a `BigDecimal` from a `bigint` value.
|
|
799
|
+
*
|
|
800
|
+
* @since 2.0.0
|
|
801
|
+
* @category constructors
|
|
802
|
+
*/
|
|
803
|
+
export const fromBigInt = (n: bigint): BigDecimal => make(n, 0)
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* Creates a `BigDecimal` from a `number` value.
|
|
807
|
+
*
|
|
808
|
+
* It is not recommended to convert a floating point number to a decimal directly,
|
|
809
|
+
* as the floating point representation may be unexpected.
|
|
810
|
+
*
|
|
811
|
+
* Throws a `RangeError` if the number is not finite (`NaN`, `+Infinity` or `-Infinity`).
|
|
812
|
+
*
|
|
813
|
+
* @example
|
|
814
|
+
* ```ts
|
|
815
|
+
* import * as assert from "node:assert"
|
|
816
|
+
* import { unsafeFromNumber, make } from "effect/BigDecimal"
|
|
817
|
+
*
|
|
818
|
+
* assert.deepStrictEqual(unsafeFromNumber(123), make(123n, 0))
|
|
819
|
+
* assert.deepStrictEqual(unsafeFromNumber(123.456), make(123456n, 3))
|
|
820
|
+
* ```
|
|
821
|
+
*
|
|
822
|
+
* @since 3.11.0
|
|
823
|
+
* @category constructors
|
|
824
|
+
*/
|
|
825
|
+
export const unsafeFromNumber = (n: number): BigDecimal =>
|
|
826
|
+
Option.getOrThrowWith(safeFromNumber(n), () => new RangeError(`Number must be finite, got ${n}`))
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* Creates a `BigDecimal` from a `number` value.
|
|
830
|
+
*
|
|
831
|
+
* It is not recommended to convert a floating point number to a decimal directly,
|
|
832
|
+
* as the floating point representation may be unexpected.
|
|
833
|
+
*
|
|
834
|
+
* Throws a `RangeError` if the number is not finite (`NaN`, `+Infinity` or `-Infinity`).
|
|
835
|
+
*
|
|
836
|
+
* @since 2.0.0
|
|
837
|
+
* @category constructors
|
|
838
|
+
* @deprecated Use {@link unsafeFromNumber} instead.
|
|
839
|
+
*/
|
|
840
|
+
export const fromNumber: (n: number) => BigDecimal = unsafeFromNumber
|
|
841
|
+
|
|
842
|
+
// TODO(4.0): Rename this to `fromNumber` after removing the current, unsafe implementation of `fromNumber`.
|
|
843
|
+
/**
|
|
844
|
+
* Creates a `BigDecimal` from a `number` value.
|
|
845
|
+
*
|
|
846
|
+
* It is not recommended to convert a floating point number to a decimal directly,
|
|
847
|
+
* as the floating point representation may be unexpected.
|
|
848
|
+
*
|
|
849
|
+
* Returns `None` if the number is not finite (`NaN`, `+Infinity` or `-Infinity`).
|
|
850
|
+
*
|
|
851
|
+
* @example
|
|
852
|
+
* ```ts
|
|
853
|
+
* import * as assert from "node:assert"
|
|
854
|
+
* import { BigDecimal, Option } from "effect"
|
|
855
|
+
*
|
|
856
|
+
* assert.deepStrictEqual(BigDecimal.safeFromNumber(123), Option.some(BigDecimal.make(123n, 0)))
|
|
857
|
+
* assert.deepStrictEqual(BigDecimal.safeFromNumber(123.456), Option.some(BigDecimal.make(123456n, 3)))
|
|
858
|
+
* assert.deepStrictEqual(BigDecimal.safeFromNumber(Infinity), Option.none())
|
|
859
|
+
* ```
|
|
860
|
+
*
|
|
861
|
+
* @since 3.11.0
|
|
862
|
+
* @category constructors
|
|
863
|
+
*/
|
|
864
|
+
export const safeFromNumber = (n: number): Option.Option<BigDecimal> => {
|
|
865
|
+
if (!Number.isFinite(n)) {
|
|
866
|
+
return Option.none()
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
const string = `${n}`
|
|
870
|
+
if (string.includes("e")) {
|
|
871
|
+
return fromString(string)
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
const [lead, trail = ""] = string.split(".")
|
|
875
|
+
return Option.some(make(BigInt(`${lead}${trail}`), trail.length))
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
/**
|
|
879
|
+
* Parses a numerical `string` into a `BigDecimal`.
|
|
880
|
+
*
|
|
881
|
+
* @example
|
|
882
|
+
* ```ts
|
|
883
|
+
* import * as assert from "node:assert"
|
|
884
|
+
* import { BigDecimal, Option } from "effect"
|
|
885
|
+
*
|
|
886
|
+
* assert.deepStrictEqual(BigDecimal.fromString("123"), Option.some(BigDecimal.make(123n, 0)))
|
|
887
|
+
* assert.deepStrictEqual(BigDecimal.fromString("123.456"), Option.some(BigDecimal.make(123456n, 3)))
|
|
888
|
+
* assert.deepStrictEqual(BigDecimal.fromString("123.abc"), Option.none())
|
|
889
|
+
* ```
|
|
890
|
+
*
|
|
891
|
+
* @since 2.0.0
|
|
892
|
+
* @category constructors
|
|
893
|
+
*/
|
|
894
|
+
export const fromString = (s: string): Option.Option<BigDecimal> => {
|
|
895
|
+
if (s === "") {
|
|
896
|
+
return Option.some(zero)
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
let base: string
|
|
900
|
+
let exp: number
|
|
901
|
+
const seperator = s.search(/[eE]/)
|
|
902
|
+
if (seperator !== -1) {
|
|
903
|
+
const trail = s.slice(seperator + 1)
|
|
904
|
+
base = s.slice(0, seperator)
|
|
905
|
+
exp = Number(trail)
|
|
906
|
+
if (base === "" || !Number.isSafeInteger(exp) || !FINITE_INT_REGEX.test(trail)) {
|
|
907
|
+
return Option.none()
|
|
908
|
+
}
|
|
909
|
+
} else {
|
|
910
|
+
base = s
|
|
911
|
+
exp = 0
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
let digits: string
|
|
915
|
+
let offset: number
|
|
916
|
+
const dot = base.search(/\./)
|
|
917
|
+
if (dot !== -1) {
|
|
918
|
+
const lead = base.slice(0, dot)
|
|
919
|
+
const trail = base.slice(dot + 1)
|
|
920
|
+
digits = `${lead}${trail}`
|
|
921
|
+
offset = trail.length
|
|
922
|
+
} else {
|
|
923
|
+
digits = base
|
|
924
|
+
offset = 0
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
if (!FINITE_INT_REGEX.test(digits)) {
|
|
928
|
+
return Option.none()
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
const scale = offset - exp
|
|
932
|
+
if (!Number.isSafeInteger(scale)) {
|
|
933
|
+
return Option.none()
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
return Option.some(make(BigInt(digits), scale))
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
/**
|
|
940
|
+
* Parses a numerical `string` into a `BigDecimal`.
|
|
941
|
+
*
|
|
942
|
+
* @example
|
|
943
|
+
* ```ts
|
|
944
|
+
* import * as assert from "node:assert"
|
|
945
|
+
* import { unsafeFromString, make } from "effect/BigDecimal"
|
|
946
|
+
*
|
|
947
|
+
* assert.deepStrictEqual(unsafeFromString("123"), make(123n, 0))
|
|
948
|
+
* assert.deepStrictEqual(unsafeFromString("123.456"), make(123456n, 3))
|
|
949
|
+
* assert.throws(() => unsafeFromString("123.abc"))
|
|
950
|
+
* ```
|
|
951
|
+
*
|
|
952
|
+
* @since 2.0.0
|
|
953
|
+
* @category constructors
|
|
954
|
+
*/
|
|
955
|
+
export const unsafeFromString = (s: string): BigDecimal =>
|
|
956
|
+
Option.getOrThrowWith(fromString(s), () => new Error("Invalid numerical string"))
|
|
957
|
+
|
|
958
|
+
/**
|
|
959
|
+
* Formats a given `BigDecimal` as a `string`.
|
|
960
|
+
*
|
|
961
|
+
* If the scale of the `BigDecimal` is greater than or equal to 16, the `BigDecimal` will
|
|
962
|
+
* be formatted in scientific notation.
|
|
963
|
+
*
|
|
964
|
+
* @example
|
|
965
|
+
* ```ts
|
|
966
|
+
* import * as assert from "node:assert"
|
|
967
|
+
* import { format, unsafeFromString } from "effect/BigDecimal"
|
|
968
|
+
*
|
|
969
|
+
* assert.deepStrictEqual(format(unsafeFromString("-5")), "-5")
|
|
970
|
+
* assert.deepStrictEqual(format(unsafeFromString("123.456")), "123.456")
|
|
971
|
+
* assert.deepStrictEqual(format(unsafeFromString("-0.00000123")), "-0.00000123")
|
|
972
|
+
* ```
|
|
973
|
+
*
|
|
974
|
+
* @since 2.0.0
|
|
975
|
+
* @category conversions
|
|
976
|
+
*/
|
|
977
|
+
export const format = (n: BigDecimal): string => {
|
|
978
|
+
const normalized = normalize(n)
|
|
979
|
+
if (Math.abs(normalized.scale) >= 16) {
|
|
980
|
+
return toExponential(normalized)
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
const negative = normalized.value < bigint0
|
|
984
|
+
const absolute = negative ? `${normalized.value}`.substring(1) : `${normalized.value}`
|
|
985
|
+
|
|
986
|
+
let before: string
|
|
987
|
+
let after: string
|
|
988
|
+
|
|
989
|
+
if (normalized.scale >= absolute.length) {
|
|
990
|
+
before = "0"
|
|
991
|
+
after = "0".repeat(normalized.scale - absolute.length) + absolute
|
|
992
|
+
} else {
|
|
993
|
+
const location = absolute.length - normalized.scale
|
|
994
|
+
if (location > absolute.length) {
|
|
995
|
+
const zeros = location - absolute.length
|
|
996
|
+
before = `${absolute}${"0".repeat(zeros)}`
|
|
997
|
+
after = ""
|
|
998
|
+
} else {
|
|
999
|
+
after = absolute.slice(location)
|
|
1000
|
+
before = absolute.slice(0, location)
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
const complete = after === "" ? before : `${before}.${after}`
|
|
1005
|
+
return negative ? `-${complete}` : complete
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/**
|
|
1009
|
+
* Formats a given `BigDecimal` as a `string` in scientific notation.
|
|
1010
|
+
*
|
|
1011
|
+
* @example
|
|
1012
|
+
* ```ts
|
|
1013
|
+
* import * as assert from "node:assert"
|
|
1014
|
+
* import { toExponential, make } from "effect/BigDecimal"
|
|
1015
|
+
*
|
|
1016
|
+
* assert.deepStrictEqual(toExponential(make(123456n, -5)), "1.23456e+10")
|
|
1017
|
+
* ```
|
|
1018
|
+
*
|
|
1019
|
+
* @since 3.11.0
|
|
1020
|
+
* @category conversions
|
|
1021
|
+
*/
|
|
1022
|
+
export const toExponential = (n: BigDecimal): string => {
|
|
1023
|
+
if (isZero(n)) {
|
|
1024
|
+
return "0e+0"
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
const normalized = normalize(n)
|
|
1028
|
+
const digits = `${abs(normalized).value}`
|
|
1029
|
+
const head = digits.slice(0, 1)
|
|
1030
|
+
const tail = digits.slice(1)
|
|
1031
|
+
|
|
1032
|
+
let output = `${isNegative(normalized) ? "-" : ""}${head}`
|
|
1033
|
+
if (tail !== "") {
|
|
1034
|
+
output += `.${tail}`
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
const exp = tail.length - normalized.scale
|
|
1038
|
+
return `${output}e${exp >= 0 ? "+" : ""}${exp}`
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
/**
|
|
1042
|
+
* Converts a `BigDecimal` to a `number`.
|
|
1043
|
+
*
|
|
1044
|
+
* This function will produce incorrect results if the `BigDecimal` exceeds the 64-bit range of a `number`.
|
|
1045
|
+
*
|
|
1046
|
+
* @example
|
|
1047
|
+
* ```ts
|
|
1048
|
+
* import * as assert from "node:assert"
|
|
1049
|
+
* import { unsafeToNumber, unsafeFromString } from "effect/BigDecimal"
|
|
1050
|
+
*
|
|
1051
|
+
* assert.deepStrictEqual(unsafeToNumber(unsafeFromString("123.456")), 123.456)
|
|
1052
|
+
* ```
|
|
1053
|
+
*
|
|
1054
|
+
* @since 2.0.0
|
|
1055
|
+
* @category conversions
|
|
1056
|
+
*/
|
|
1057
|
+
export const unsafeToNumber = (n: BigDecimal): number => Number(format(n))
|
|
1058
|
+
|
|
1059
|
+
/**
|
|
1060
|
+
* Checks if a given `BigDecimal` is an integer.
|
|
1061
|
+
*
|
|
1062
|
+
* @example
|
|
1063
|
+
* ```ts
|
|
1064
|
+
* import * as assert from "node:assert"
|
|
1065
|
+
* import { isInteger, unsafeFromString } from "effect/BigDecimal"
|
|
1066
|
+
*
|
|
1067
|
+
* assert.deepStrictEqual(isInteger(unsafeFromString("0")), true)
|
|
1068
|
+
* assert.deepStrictEqual(isInteger(unsafeFromString("1")), true)
|
|
1069
|
+
* assert.deepStrictEqual(isInteger(unsafeFromString("1.1")), false)
|
|
1070
|
+
* ```
|
|
1071
|
+
*
|
|
1072
|
+
* @since 2.0.0
|
|
1073
|
+
* @category predicates
|
|
1074
|
+
*/
|
|
1075
|
+
export const isInteger = (n: BigDecimal): boolean => normalize(n).scale <= 0
|
|
1076
|
+
|
|
1077
|
+
/**
|
|
1078
|
+
* Checks if a given `BigDecimal` is `0`.
|
|
1079
|
+
*
|
|
1080
|
+
* @example
|
|
1081
|
+
* ```ts
|
|
1082
|
+
* import * as assert from "node:assert"
|
|
1083
|
+
* import { isZero, unsafeFromString } from "effect/BigDecimal"
|
|
1084
|
+
*
|
|
1085
|
+
* assert.deepStrictEqual(isZero(unsafeFromString("0")), true)
|
|
1086
|
+
* assert.deepStrictEqual(isZero(unsafeFromString("1")), false)
|
|
1087
|
+
* ```
|
|
1088
|
+
*
|
|
1089
|
+
* @since 2.0.0
|
|
1090
|
+
* @category predicates
|
|
1091
|
+
*/
|
|
1092
|
+
export const isZero = (n: BigDecimal): boolean => n.value === bigint0
|
|
1093
|
+
|
|
1094
|
+
/**
|
|
1095
|
+
* Checks if a given `BigDecimal` is negative.
|
|
1096
|
+
*
|
|
1097
|
+
* @example
|
|
1098
|
+
* ```ts
|
|
1099
|
+
* import * as assert from "node:assert"
|
|
1100
|
+
* import { isNegative, unsafeFromString } from "effect/BigDecimal"
|
|
1101
|
+
*
|
|
1102
|
+
* assert.deepStrictEqual(isNegative(unsafeFromString("-1")), true)
|
|
1103
|
+
* assert.deepStrictEqual(isNegative(unsafeFromString("0")), false)
|
|
1104
|
+
* assert.deepStrictEqual(isNegative(unsafeFromString("1")), false)
|
|
1105
|
+
* ```
|
|
1106
|
+
*
|
|
1107
|
+
* @since 2.0.0
|
|
1108
|
+
* @category predicates
|
|
1109
|
+
*/
|
|
1110
|
+
export const isNegative = (n: BigDecimal): boolean => n.value < bigint0
|
|
1111
|
+
|
|
1112
|
+
/**
|
|
1113
|
+
* Checks if a given `BigDecimal` is positive.
|
|
1114
|
+
*
|
|
1115
|
+
* @example
|
|
1116
|
+
* ```ts
|
|
1117
|
+
* import * as assert from "node:assert"
|
|
1118
|
+
* import { isPositive, unsafeFromString } from "effect/BigDecimal"
|
|
1119
|
+
*
|
|
1120
|
+
* assert.deepStrictEqual(isPositive(unsafeFromString("-1")), false)
|
|
1121
|
+
* assert.deepStrictEqual(isPositive(unsafeFromString("0")), false)
|
|
1122
|
+
* assert.deepStrictEqual(isPositive(unsafeFromString("1")), true)
|
|
1123
|
+
* ```
|
|
1124
|
+
*
|
|
1125
|
+
* @since 2.0.0
|
|
1126
|
+
* @category predicates
|
|
1127
|
+
*/
|
|
1128
|
+
export const isPositive = (n: BigDecimal): boolean => n.value > bigint0
|
|
1129
|
+
|
|
1130
|
+
const isBigDecimalArgs = (args: IArguments) => isBigDecimal(args[0])
|
|
1131
|
+
|
|
1132
|
+
/**
|
|
1133
|
+
* Calculate the ceiling of a `BigDecimal` at the given scale.
|
|
1134
|
+
*
|
|
1135
|
+
* @example
|
|
1136
|
+
* ```ts
|
|
1137
|
+
* import * as assert from "node:assert"
|
|
1138
|
+
* import { ceil, unsafeFromString } from "effect/BigDecimal"
|
|
1139
|
+
*
|
|
1140
|
+
* assert.deepStrictEqual(ceil(unsafeFromString("145"), -1), unsafeFromString("150"))
|
|
1141
|
+
* assert.deepStrictEqual(ceil(unsafeFromString("-14.5")), unsafeFromString("-14"))
|
|
1142
|
+
* ```
|
|
1143
|
+
*
|
|
1144
|
+
* @since 3.16.0
|
|
1145
|
+
* @category math
|
|
1146
|
+
*/
|
|
1147
|
+
export const ceil: {
|
|
1148
|
+
(scale: number): (self: BigDecimal) => BigDecimal
|
|
1149
|
+
(self: BigDecimal, scale?: number): BigDecimal
|
|
1150
|
+
} = dual(isBigDecimalArgs, (self: BigDecimal, scale: number = 0): BigDecimal => {
|
|
1151
|
+
const truncated = truncate(self, scale)
|
|
1152
|
+
|
|
1153
|
+
if (isPositive(self) && lessThan(truncated, self)) {
|
|
1154
|
+
return sum(truncated, make(1n, scale))
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
return truncated
|
|
1158
|
+
})
|
|
1159
|
+
|
|
1160
|
+
/**
|
|
1161
|
+
* Calculate the floor of a `BigDecimal` at the given scale.
|
|
1162
|
+
*
|
|
1163
|
+
* @example
|
|
1164
|
+
* ```ts
|
|
1165
|
+
* import * as assert from "node:assert"
|
|
1166
|
+
* import { floor, unsafeFromString } from "effect/BigDecimal"
|
|
1167
|
+
*
|
|
1168
|
+
* assert.deepStrictEqual(floor(unsafeFromString("145"), -1), unsafeFromString("140"))
|
|
1169
|
+
* assert.deepStrictEqual(floor(unsafeFromString("-14.5")), unsafeFromString("-15"))
|
|
1170
|
+
* ```
|
|
1171
|
+
*
|
|
1172
|
+
* @since 3.16.0
|
|
1173
|
+
* @category math
|
|
1174
|
+
*/
|
|
1175
|
+
export const floor: {
|
|
1176
|
+
(scale: number): (self: BigDecimal) => BigDecimal
|
|
1177
|
+
(self: BigDecimal, scale?: number): BigDecimal
|
|
1178
|
+
} = dual(isBigDecimalArgs, (self: BigDecimal, scale: number = 0): BigDecimal => {
|
|
1179
|
+
const truncated = truncate(self, scale)
|
|
1180
|
+
|
|
1181
|
+
if (isNegative(self) && greaterThan(truncated, self)) {
|
|
1182
|
+
return sum(truncated, make(-1n, scale))
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
return truncated
|
|
1186
|
+
})
|
|
1187
|
+
|
|
1188
|
+
/**
|
|
1189
|
+
* Truncate a `BigDecimal` at the given scale. This is the same operation as rounding away from zero.
|
|
1190
|
+
*
|
|
1191
|
+
* @example
|
|
1192
|
+
* ```ts
|
|
1193
|
+
* import * as assert from "node:assert"
|
|
1194
|
+
* import { truncate, unsafeFromString } from "effect/BigDecimal"
|
|
1195
|
+
*
|
|
1196
|
+
* assert.deepStrictEqual(truncate(unsafeFromString("145"), -1), unsafeFromString("140"))
|
|
1197
|
+
* assert.deepStrictEqual(truncate(unsafeFromString("-14.5")), unsafeFromString("-14"))
|
|
1198
|
+
* ```
|
|
1199
|
+
*
|
|
1200
|
+
* @since 3.16.0
|
|
1201
|
+
* @category math
|
|
1202
|
+
*/
|
|
1203
|
+
export const truncate: {
|
|
1204
|
+
(scale: number): (self: BigDecimal) => BigDecimal
|
|
1205
|
+
(self: BigDecimal, scale?: number): BigDecimal
|
|
1206
|
+
} = dual(isBigDecimalArgs, (self: BigDecimal, scale: number = 0): BigDecimal => {
|
|
1207
|
+
if (self.scale <= scale) {
|
|
1208
|
+
return self
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
// BigInt division truncates towards zero
|
|
1212
|
+
return make(self.value / (10n ** BigInt(self.scale - scale)), scale)
|
|
1213
|
+
})
|
|
1214
|
+
|
|
1215
|
+
/**
|
|
1216
|
+
* Internal function used by `round` for `half-even` and `half-odd` rounding modes.
|
|
1217
|
+
*
|
|
1218
|
+
* Returns the digit at the position of the given `scale` within the `BigDecimal`.
|
|
1219
|
+
*
|
|
1220
|
+
* @internal
|
|
1221
|
+
*/
|
|
1222
|
+
export const digitAt: {
|
|
1223
|
+
(scale: number): (self: BigDecimal) => bigint
|
|
1224
|
+
(self: BigDecimal, scale: number): bigint
|
|
1225
|
+
} = dual(2, (self: BigDecimal, scale: number): bigint => {
|
|
1226
|
+
if (self.scale < scale) {
|
|
1227
|
+
return 0n
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
const scaled = self.value / (10n ** BigInt(self.scale - scale))
|
|
1231
|
+
return scaled % 10n
|
|
1232
|
+
})
|
|
1233
|
+
|
|
1234
|
+
/**
|
|
1235
|
+
* Rounding modes for `BigDecimal`.
|
|
1236
|
+
*
|
|
1237
|
+
* `ceil`: round towards positive infinity
|
|
1238
|
+
* `floor`: round towards negative infinity
|
|
1239
|
+
* `to-zero`: round towards zero
|
|
1240
|
+
* `from-zero`: round away from zero
|
|
1241
|
+
* `half-ceil`: round to the nearest neighbor; if equidistant round towards positive infinity
|
|
1242
|
+
* `half-floor`: round to the nearest neighbor; if equidistant round towards negative infinity
|
|
1243
|
+
* `half-to-zero`: round to the nearest neighbor; if equidistant round towards zero
|
|
1244
|
+
* `half-from-zero`: round to the nearest neighbor; if equidistant round away from zero
|
|
1245
|
+
* `half-even`: round to the nearest neighbor; if equidistant round to the neighbor with an even digit
|
|
1246
|
+
* `half-odd`: round to the nearest neighbor; if equidistant round to the neighbor with an odd digit
|
|
1247
|
+
*
|
|
1248
|
+
* @since 3.16.0
|
|
1249
|
+
* @category math
|
|
1250
|
+
*/
|
|
1251
|
+
export type RoundingMode =
|
|
1252
|
+
| "ceil"
|
|
1253
|
+
| "floor"
|
|
1254
|
+
| "to-zero"
|
|
1255
|
+
| "from-zero"
|
|
1256
|
+
| "half-ceil"
|
|
1257
|
+
| "half-floor"
|
|
1258
|
+
| "half-to-zero"
|
|
1259
|
+
| "half-from-zero"
|
|
1260
|
+
| "half-even"
|
|
1261
|
+
| "half-odd"
|
|
1262
|
+
|
|
1263
|
+
/**
|
|
1264
|
+
* Rounds a `BigDecimal` at the given scale with the specified rounding mode.
|
|
1265
|
+
*
|
|
1266
|
+
* @example
|
|
1267
|
+
* ```ts
|
|
1268
|
+
* import * as assert from "node:assert"
|
|
1269
|
+
* import { round, unsafeFromString } from "effect/BigDecimal"
|
|
1270
|
+
*
|
|
1271
|
+
* assert.deepStrictEqual(round(unsafeFromString("145"), { mode: "from-zero", scale: -1 }), unsafeFromString("150"))
|
|
1272
|
+
* assert.deepStrictEqual(round(unsafeFromString("-14.5")), unsafeFromString("-15"))
|
|
1273
|
+
* ```
|
|
1274
|
+
*
|
|
1275
|
+
* @since 3.16.0
|
|
1276
|
+
* @category math
|
|
1277
|
+
*/
|
|
1278
|
+
export const round: {
|
|
1279
|
+
(options: { scale?: number; mode?: RoundingMode }): (self: BigDecimal) => BigDecimal
|
|
1280
|
+
(n: BigDecimal, options?: { scale?: number; mode?: RoundingMode }): BigDecimal
|
|
1281
|
+
} = dual(isBigDecimalArgs, (self: BigDecimal, options?: { scale?: number; mode?: RoundingMode }): BigDecimal => {
|
|
1282
|
+
const mode = options?.mode ?? "half-from-zero"
|
|
1283
|
+
const scale = options?.scale ?? 0
|
|
1284
|
+
|
|
1285
|
+
switch (mode) {
|
|
1286
|
+
case "ceil":
|
|
1287
|
+
return ceil(self, scale)
|
|
1288
|
+
|
|
1289
|
+
case "floor":
|
|
1290
|
+
return floor(self, scale)
|
|
1291
|
+
|
|
1292
|
+
case "to-zero":
|
|
1293
|
+
return truncate(self, scale)
|
|
1294
|
+
|
|
1295
|
+
case "from-zero":
|
|
1296
|
+
return (isPositive(self) ? ceil(self, scale) : floor(self, scale))
|
|
1297
|
+
|
|
1298
|
+
case "half-ceil":
|
|
1299
|
+
return floor(sum(self, make(5n, scale + 1)), scale)
|
|
1300
|
+
|
|
1301
|
+
case "half-floor":
|
|
1302
|
+
return ceil(sum(self, make(-5n, scale + 1)), scale)
|
|
1303
|
+
|
|
1304
|
+
case "half-to-zero":
|
|
1305
|
+
return isNegative(self)
|
|
1306
|
+
? floor(sum(self, make(5n, scale + 1)), scale)
|
|
1307
|
+
: ceil(sum(self, make(-5n, scale + 1)), scale)
|
|
1308
|
+
|
|
1309
|
+
case "half-from-zero":
|
|
1310
|
+
return isNegative(self)
|
|
1311
|
+
? ceil(sum(self, make(-5n, scale + 1)), scale)
|
|
1312
|
+
: floor(sum(self, make(5n, scale + 1)), scale)
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
const halfCeil = floor(sum(self, make(5n, scale + 1)), scale)
|
|
1316
|
+
const halfFloor = ceil(sum(self, make(-5n, scale + 1)), scale)
|
|
1317
|
+
const digit = digitAt(halfCeil, scale)
|
|
1318
|
+
|
|
1319
|
+
switch (mode) {
|
|
1320
|
+
case "half-even":
|
|
1321
|
+
return equals(halfCeil, halfFloor) ? halfCeil : (digit % 2n === 0n) ? halfCeil : halfFloor
|
|
1322
|
+
|
|
1323
|
+
case "half-odd":
|
|
1324
|
+
return equals(halfCeil, halfFloor) ? halfCeil : (digit % 2n === 0n) ? halfFloor : halfCeil
|
|
1325
|
+
}
|
|
1326
|
+
})
|
|
1327
|
+
|
|
1328
|
+
/**
|
|
1329
|
+
* Takes an `Iterable` of `BigDecimal`s and returns their sum as a single `BigDecimal`
|
|
1330
|
+
*
|
|
1331
|
+
* @example
|
|
1332
|
+
* ```ts
|
|
1333
|
+
* import * as assert from "node:assert"
|
|
1334
|
+
* import { unsafeFromString, sumAll } from "effect/BigDecimal"
|
|
1335
|
+
*
|
|
1336
|
+
* assert.deepStrictEqual(sumAll([unsafeFromString("2"), unsafeFromString("3"), unsafeFromString("4")]), unsafeFromString("9"))
|
|
1337
|
+
* ```
|
|
1338
|
+
*
|
|
1339
|
+
* @category math
|
|
1340
|
+
* @since 3.16.0
|
|
1341
|
+
*/
|
|
1342
|
+
export const sumAll = (collection: Iterable<BigDecimal>): BigDecimal => {
|
|
1343
|
+
let out = zero
|
|
1344
|
+
for (const n of collection) {
|
|
1345
|
+
out = sum(out, n)
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
return out
|
|
1349
|
+
}
|