-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
std/int128s
and type Duration = distinct int128
#399
Comments
The only nit I have: do we really have to suffix every module name with |
module names where a symbol of same name exists causes issues though, and the s also reminds that there is not just int128 but also uint128. module-symbol name clash example(hence nim-lang/Nim#15590) # in std/int128:
type int128* = object
data: array[2, uint64] # fallback impl
proc high*[T: int128](_: typedesc[T]): int128 = int128(data: [uint64.high, uint64.high])
# value not correct but that's beside the point
# (also besides the point is whether high should be defined) # main.nim:
import std/int128
echo int128.high would give: in other cases it could be even more error prone, silently giving un-intended results. using |
My only opinion on this is that I rather just have this type present in system.nim (or at least, imported implicitly). |
No... |
I've always been in favor of having int128/uint128 as built-in types, but nothing against them being a std package. I also wrote a 128-bit integer nimble package, nint128. I decided to write it because I believe it is possible to do more optimizations on a single type of integer than using arbitrary integers. In it I tried to write everything in pure Nim, with some optimizations using __int128 or intrinsics, when possible and really favoring the code. I'm currently evolving the package to be fully pure Nim with the user being able to determine which operators should use __int128 (C extension for 128-bit integers, which is supported by GCC and CLANG) or intrinsic functions for 128-bit VCC. |
Why? I understand why things like, say, sequtils aren't in system.nim - it puts increased load on the compiler, and makes resolving name clashes harder - but I don't see why basic data types must be excluded. |
"Basic data types" don't mean anything to me, we lived for 10 years without int128 but once added it's "basic"? Would a BigInt also be "basic" then? Instead we should make system.nim smaller, not bigger. It's pointless to optimize for the case "what can you write without an import statement" as already no real program out there can be written without an import. |
I am in favor of a "high resolution value dense numeric" time type. I am also in favor of some However, I think 64-bits gets you Meanwhile, only 53 bits of an IEEE double also get you Actual change to time type representation should be discussed over in #383, though. I comment here because my points pertain more to the example. |
Having 128-bit uint support would drastically improve the performance of any 128-bit decimal library that conforms to the IEEE standard as it does a lot of 113-bit arithmetic. (This does remind me that I need to re-arrange my life somehow so that I can resume work on the decimal library.) But whether it is me or someone else, it would be a huge performance boost on machines that happen to actually have CPU/APU/GPU 128-bit math support; which many modern ones do. |
Stripe about |
proposal
add a
std/int128s
module containing 2 types: int128 and uint128The API would be similar to std/jsbigints (https://nim-lang.github.io/Nim/jsbigints.html)
example use case 1:
type Duration = distinct int128
one perfect use case is for representing
Duration
.Duration
currently uses a sub-optimal designwhich forces every operation to be more costly than needed, and has underlying invalid bit representations. Using
type Duration = distinct int128
would be much more natural, and efficient.I consider this RFC as a pre-requisit for #383
(APIs should have typesafe self-documenting time units, eg proc sleep(t: Duration), allowing sleep(1.millisecond) etc
Note: whether
Duration
can be re-defined astype Duration = distinct int128
is TBD, but even if backward compatibility prevents it, we can still define std/durations definingtype TimeUnit = distinct int128
and use it throughout stdlib to represent durations in APIS (ie, for #383); and std/times can use a conversionTimeUnit <=> Duration
example use case 2: compiler/int128 could reuse std/int128s
(and benefit from performance when native type is used)
why not use std/bigints instead?
std/bigints
is also tracked and should eventually make its way in stdlib, but is no replacement for int128, for several reasons:std/bigints
to represent 128 intsimplementation
most C compilers support this natively.
__int128
, wrap native operators (+, / etc) via importc procs; backend support can be done via#ifdef __SIZEOF_INT128__
(refs https://stackoverflow.com/questions/16088282/is-there-a-128-bit-integer-in-gcc/54815033#54815033); the check can be done at CT without having to use a custom flag (simpler than what we did withNIM_EmulateOverflowChecks
)lib/std/private/int128s
)Note, I've already implemented a lot of this, and it's just as easy to use as native types (eg int64) on the client side
importc for operators
std/jsbigints can write this:
but that doesn't work with importc (it requires importcpp, which requires cpp backend).
What i did to circumvent this is to use an auxiliary .h file containing macros which i can then importc and it all works, but in future work this should be improved so that we can use the much simpler and direct way:
refs #315 (comment) which shows what should be done (that RFC needs to be updated to define pattern instead of improving importjs)
current unknown: what should be the type kind?
this works (in particular has value semantics), but what's unclear is whether it should be "object" or something else on the RHS; it doesn't follow what the other integral types do (tyInt64 etc).
for eg, in js backend this is what's used instead of object:
tyInt64
etc, by introducingtyInt128
andtyUInt128
but the obvious downside is this would increase compiler complexitytyInteger
(all ints) ortyNumber
(all numbers) to also represent float in extended precision (float80), quadruple floats (float128, akalong double
), or half-float (float16) using 1 type kind, or at least for all new such types (excluding tyInt32 etc)bigint vs 128 performance
links
type TimeUnit = distinct int128
timotheecour/Nim#762 which was a draft of this RFC; see some implementation discussion here:type TimeUnit = distinct int128
timotheecour/Nim#762 (comment)proc sleep(t: Duration)
, allowingsleep(1.millisecond)
etc #383 (comment)Int128
, so this is a candidate thing to compare againststd/times
by konsumlamm · Pull Request #18378 · nim-lang/NimThe text was updated successfully, but these errors were encountered: