11 ms·
I’m hoping that https://github.com/golang/go/issues/19623 https://github.com/golang/go/issues/19623 will come through, and we’ll get a native “true integer” typ
by joppy 8y ago
I’m hoping that https://github.com/golang/go/issues/19623 https://github.com/golang/go/issues/19623 will come through, and we’ll get a native “true integer” type (and hopefully a rational one as well, though maybe this is pushing it a bit). This is really something that should be implemented at the language level, so that “int” can become a true integer, yet still remain efficient in many cases.
It is bizarre to me that languages boasting built-in language-level data structures like lists, hashtables, etc are content to just leave us with the bare minimum support of numbers, being basically whatever the hardware thinks a number is. The semantics of integers and fractions are perfect, and everybody already knows them. On the other hand, overflows in int32’s are weird, and if your idea of a fraction is a floating-point number, then you can never have something like (5/3)*6 evaluate to 10 exactly.
To be clear, I think fixed-width integers and floating-point numbers have their place, I just see no reason why they should be the default.
- a_c_s 8y agoThis was one thing COBOL got right: built in support for a DECIMAL data type.
- prevedmedved 8y agoDon't be stupid. A "decimal" type is a floating-point number, just with a different base. It solves none of the underlying problems. (Which is why, incidentally, nothing made in this millennium supports it.)
- christophilus 8y agoIt’s been a while since I COBOLed, but if I recall, the COBOL decimal is similar to Currency types in languages like C#. (Maybe I’m misremembering.) If I’m right, though, it’s not a floating point number. It’s currency properly handled via integer math under the hood.
- Symmetry 8y agoDecimal floating point is actually an established thing and part of the current IEEE 754 spec. I'm not too familiar with COBOL but pretty much any modern language will offer it through a library or compiler extension. Recent IBM Power processors even have hardware support. https://en.wikipedia.org/wiki/Decimal_floating_point https://en.wikipedia.org/wiki/Decimal_floating_point
- ekimekim 8y agoBoth you and the parent are correct. Decimal floating point is a long-established thing, but the vast majority of "Currency" or "Decimal" data types in modern languages are arbitrary or fixed precision (to some configurable precision) which uses integer math under the hood.
- deleted 8y ago[deleted]
- vanderZwan 8y agoGiven the age of COBOL and the age of IEEE floating points, it would be very unlikely if it used a floating point number. (And yes, I know that Conrad Zuse invented floating point over a century ago ;))
- michaelcampbell 8y agoProbably implementation dependent, but the COBOL I used that put me through college used some variation of BCD (binary coded decimal).
- coldtea 8y agoCobol uses fixed point decimal
- int_19h 8y agoIn C#, there's a "decimal" type. Which is exactly that - decimal floating-point. However, one catch about it is that it doesn't allow for the exponent that would place the decimal point somewhere outside of the representable digits of the number (i.e. unlike floats, the difference between any two decimals is never more than 1). But it's still plenty useful, because it allows to accurately represent decimal fractional numbers, which is exactly what's needed in many domains, since humans work with decimal fractional numbers. Representing money would be one particular example.
- vvern 8y agoFixed – Fixed-place decimal math library for Go (github.com) https://news.ycombinator.com/item?id=18559625 https://news.ycombinator.com/item?id=18559625
- igravious 8y agoThat would be quite a fundamental change. At the moment _int_ and _uint_ have certain semantics that, if changed, would surely break many applications and libraries that rely on the current semantics. I am finding it hard to think of a more sweeping and drastic change to the core of a language. Having said that, I'm by no means a Golang expert – this is the comment of an outsider looking in. I get that the proposer is Rob Pike and obviously Mr. Pike is god-like so what is it I am missing? Is Go 2 meant to break everything? That's like, wow. Any low-level hardware bit-banging code is going to have to be audited or break in subtle ways, will it not? Is Golang different from C and C++ and languages of that ilk that this sort of change is not that much of a problem? Help me out here folks, I'm genuinely perplexed.
- pstuart 8y agoIf these are new datatypes then they would break nothing (ignoring the "int" default part). > so what is it I am missing? The Go team has been adamant about avoiding any changes that break existing code. The whole point of Go 2 is that at some point that might have to happen and they're trying to minimize that pain.
- HALtheWise 8y agoIf the change as originally proposed went through, it probably wouldn't affect most uses of bitbanging low level code because they are already using int32/int64 rather than int (which has different size on different platforms). You are correct that it could definitely break some programs though, and so with recent sensibilities veering away from making any non- backwards-compatible changes, an amended proposal would probably just introduce a new "vint" type (maybe removing the old int type at the same time if it is really ambitious)
- copperx 8y agoI've been thinking about this, and even though it's indeed a breaking change, it's one of those changes that can be easily toggled through a compiler flag. I cannot picture many libraries relying on the edge cases that Pike enumerated.
- 13415 8y agoMakes no sense to me to redefine existing integer types. Why not introduce a primitive type "num" for arbitrary precision rational numbers instead? As a long-time Racket and Scheme user, I'd say that arbitrary precision numbers as default bring more disadvantages than advantages. As an option with syntax support Yes, but not as a default. it just makes it harder to port all kinds of code that relies on modulo arithmetics.
- outworlder 8y agoThis is reminiscent of 'numeric tower' discussions from years ago.
- coder543 8y ago> it just makes it harder to port all kinds of code that relies on modulo arithmetics. If you're relying on modulo arithmetic, you should be using a fixed size integer anyways, not one that varies based on the architecture. Go has fixed size integer types available, and modulo arithmetic should be using those, not "int".
- viraptor 8y agoI'm not sure how these two are related. Why would you mix modulo operations and fixed size? Modulo on an arbitrary bigint is perfectly valid and useful.
- coder543 8y agoModulo arithmetic refers to the property of fixed-size integers where they will predictably wraparound in expected ways if you overflow or underflow them. This wraparound is "free", so it used to be commonly used for cyclic high performance code. An arbitrary bigint is computationally more expensive, and it will never experience this effect, so it's a double whammy of irrelevance for bigints. You can manually do a modulo operation on a bigint, but that just makes them even more computationally expensive than a fixed size int, requires more code, and would be considered an unnecessary inconvenience by most people who care about modulo arithmetic.
- tigershark 8y agoI am misunderstanding or really go is using the ‘int’ type that can be 32 or 64 bit depending on the system that it runs on??? If this is the case I think that is crazy and I can’t think of any useful use case for it. If it’s not the case then please explain me what that proposal is really about...
- pkulak 8y agoYou are not crazy, and it's what makes this proposal even more appropriate than other languages. "int" is already a magic type.
- nwmcsween 8y agoIts not crazy, its defined by the system ABI, C, C++ has this too in that can be whatever depending on the ABI, hell char can be 32 bits.
- Sharlin 8y agoIt may be crazy but it's not exactly without precedent. Neither C nor C++ fix the sizes of the fundamental integer types, although for backward-compatibility reasons popular 64-bit platforms still have 32-bit `int` and even `long`. But yeah, there's a reason eg. Rust has no `int` and friends but `i32` etc. instead.
- user5994461 8y agoC only defines char, short, int has having a minimum size of 8, 16 and 32 bits.
- the_clarence 8y agoWhy oh why do people want a value to have different bounds depending on which system it is used? This is a source of huge confusion and why people stick to uint8 and other precise types
- drb91 8y agoPeople have traditionally wanted to use the maximum sized type that can fit in a register.
- user5994461 8y agoTraditionally the register size was too small, it's very common to have numbers above 256 or 65536. It's not true anymore with 32 bits numbers and a limit of 2 billion.
- Someone 8y agoMore precisely: they wanted the integer type that was large enough and ran their code fastest. On CPUs with 64-bit and 32-bit registers, that typically is the register-sized integer type. Machines with 16-bit registers are a bit of an edge case, as 16-bit integers may both be a lot faster on them then 32-bit integers and, in many cases, too small) If go chose to use 32-bit integers as default, some users on 64-bit systems would complain that they couldn’t create, say, an array of 6 billion ints. If they chose 64-bit, some users on 32-bit systems would complain their loops were needlessly slow, and code bloated (why waste 4 bytes of almost every integer in a program?) Not having generics makes this more of a problem. If go had generics, switching between integer sizes could be a matter of recompilation using a different compiler flag) A sufficiently advanced compiler would help here, but go doesn’t have one (not exceptional), and doesn’t even aim to have one (compilation speed seems more of a goal than run-time speed)
- TheDong 8y ago> Not having generics makes this more of a problem. If go had generics, switching between integer sizes could be a matter of recompilation using a different compiler flag) Isn't it already the case that you can switch between int sizes with compiler flags? var i int That will be 32 bits if I compile it with GOOS=linux GOARCH=386 and will be 32 bits if I swap in amd64 instead of 386 there. Is there any language where generics are useful for switching between int sizes? None come to mind offhand, so I don't quite understand what you mean.
- quickthrower2 8y agoMeh I use C# and I rarely need an int bigger than 2147483647, and if I do I use a long which gets me up to 9223372036854775807, and if I need more than THAT then I'll use a math library of some sort.
- deleted 8y ago[deleted]
- adtac 8y agoThe problem with overflow isn't just needing to store numbers larger than 2 billion. Sometimes, intermediate values are larger than that even if the final result isn't. Take averaging as a very simple example. Doing (a + b) / 2 will overflow if a and b are sufficiently large, even if the average will always fit in 32 bits. Things like this go unseen for years.
- dekhn 8y agodon't most people compute the mean iteratively when they need to do this? Sure, it goes unseen, but programmers on systems like this are expected to understand the math model and write tests.
- xapata 8y agoSystems like what? My expectation is no, most people make mistakes.
- dekhn 8y agoI mean, in C and other low-level languages unlike python, it's generally assumed you have a basic understanding of the machine model and the consequences of arithmetic in limited types. If most people make mistakes, they should self-select to languages which have properties that protect them from their ignorance. for example, I mostly program in Python using longs so I don't have to worry about overflow.
- Insanity 8y agoI'd like this because it'd make certain classes of programming problems simpler. Admittedly, not for things I build in my day-job but mostly for the kind of things you'd get when doing 'project euler' or 'leetcode'. Or more seasonal, the coming "Advent of Code".
- jolmg 8y agoI like how Haskell does it. When you simply write a number like "3" it will infer the type to be "Num a => a" which means it could be any type you have loaded that defines the functions in the typeclass Num: class Num a where (+) :: a -> a -> a (-) :: a -> a -> a (*) :: a -> a -> a negate :: a -> a abs :: a -> a signum :: a -> a fromInteger :: Integer -> a "3.0" would be "Fractional a => a" which means it defines the functions in the typeclass Fractional (in addition to being a Num): class Num a => Fractional a where (/) :: a -> a -> a recip :: a -> a fromRational :: Rational -> a Depending on how you use the value, the type would be further refined in compile-time. For example, if you did `recip 3`, 3 couldn't be any Num anymore, it would have to be some Fractional. Regarding (5/3)*6, it does equal 10 using floating point. A better example would be how 0.1 + 0.2 is not equal to 0.3. We can see this: ghci> 0.1 + 0.2 == (0.3 :: Float) False If we specified that we're working with Rational values, which are also Fractional a => a, and which are defined as a pair of integers, one representing a numerator and the other a denominator, roughly like so: type Rational = Ratio Integer data Ratio a = a :% a then we can see that 0.1 + 0.2 does equal to 0.3: ghci> 0.1 + 0.2 == (0.3 :: Rational) True It's pretty cool that Haskell lets you define new types of numbers and use them like any other. While you can transparently support hardware type numbers, represented by types like Int, Float, Double, Word, Word8, Word16, Word32, Word64, you also have transparent support for arbitrary precision Integer and Rational. Writing your functions to work with the typeclasses like Num and Fractional lets your functions work with any of these types and future types defined.
- joppy 8y agoThis is a great system for tying in new number types with existing ones, but the lack of explicitness about casting exact types (Integer, Rational) to inexact types (Int, Float) has led to many bugs and confusions for me. Coupled with the fact that so many standard functions (like length, for example) want to return an Int rather than an Integer, it just leads to me spewing ((fromIntegral ___)::Integer) all over my code. I love all of the automatic casting between exact types, but happily implicitly casting to inexact types is (in my opinion) a big mistake.
- 8y ago
- LanceH 8y agoI don't know how many times I've been writing a program using int, then suddenly I have to do some math on the index of a range (for example), and the math.* functions require int64. I start casting to int64, but things get infected and it spreads. Eventually I refactor everything to use int64 and wonder why int can't just be an alias for one of the others. Personally I would make it int64, since that is what the standard library thinks math should be done with.
- benhoyt 8y agoOdd, I've rarely had this issue, and almost never need to do complicated math on the index of a range (maybe "multiply by two and add one" kind of stuff, but nothing from the "math" pkg). Also, note that the math.* functions all use float64, not in64.
- LanceH 8y agoYes, you're right float64 in the math package. So I've definitely run into this with float vs float64. As for the int vs int64, I definitely run into what I describe on Project Euler. Probably using a self referential map[int]int when I need to suddenly pull an int64 and everything gets infected. I realize it's just a matter of convenience for me, but I personally have no downside to int == int64.
- losvedir 8y agoMy (admittedly unsophisticated) mental model is that int32 and the like are simple primitives that can be stored in registers and use the processor's native ADD/MUL codes, while BigInt is going to be some boxed structure with its own implementation of arithmetic operations. For as common as number munging is (especially in somewhat lower level code that Go shoots for), it would carry a huge performance penalty, wouldn't it? Or are there more sophisticated ways of offering a "true integer" type that I'm not aware of?