<p>What are the downsides to having different data types for floats and integers instead of just a number data type? I know that having different ones can improve memory usage. But are there any downsides other than some programmers using the language may not like it?</p>
<p>Credit to <a href="https://area51.stackexchange.com/users/210228/mathcat">Math Cat</a> for <a href="https://area51.stackexchange.com/proposals/127456/programming-language-design-and-implementation/127718#127718">the original A51 question</a></p>

<language-design><numbers>
What are the downsides of having types for floats and integers?
<p>The main advantage of having a number type is simplicity and ease of use. Many versions of BASIC just had floating point numbers, which reduced the size of the code (given that the first home computer, which Bill Gates wrote the BASIC for, had only 4K of memory, this was very important) and made it so that beginning programmers didn't have to learn the difference between integers and floats, everything just being numbers.</p>
<p>Code size is no longer an issue; few deal with systems with less than 1MB of memory. When writing a language for a beginning audience, especially children, I can still see the value in simplifying that detail.</p>

CC BY-SA 4.0
2023-05-16T20:26:16.807Z
2023-05-16T20:26:16.807Z
prosfilaes
<p>The problem with having only a single number type is: <em>which number type do you pick</em>?</p>
<p>For a good example of what <em>not</em> to do, you have to look no further than the most widely-used (depending on definition) programming language, JavaScript. JavaScript had for a very long time only a single number type, a IEEE 754-2019 / ISO/IEC 60559:2020 <em>binary64</em> floating point number.</p>
<p>There are two problems with this. Everybody knows about the limitations of floating point with its fixed precision and accuracy, and that's what everybody is focusing on, but that's only half the story. There is another problem here: the fact that it is a <em>binary</em> representation.</p>
<p>For the majority of real-world problems, by which I mean the kinds of problems which casual programmers and business programmers encounter, we are dealing with <em>decimal</em> numbers. Whether that's money, distances, speeds, weights, areas, volumes, percentages, etc. And users have an intuition about those: they know that 1/3 cannot be represented in decimal, they know that π cannot be represented in any integer base, but they are <em>very surprised</em> by the fact that JavaScript cannot represent 0.1.</p>
<p>I would argue that a programming language that does not have a good reason to do so (e.g. a language specifically for cryptography) should choose base-10 as the default number representation. I would also argue that arbitrary precision decimal rationals are a better default type than either floats or integers. I.e. make <code>12.34</code> syntactic sugar for <code>1234/100</code> and <code>12.34%</code> syntactic sugar for <code>1234/100/100</code>.</p>
<p>Arbitrary precision decimal rationals will work as long as you restrict the operations to addition, subtraction, multiplication, and division, as well as exponentiation by a natural number. For most users, those should be enough. Heck, I would bet a good sum of money that a significant portion of users don't even know that an exponent can be negative or non-integer!</p>
<p>It gets more interesting when you get into geometry, though. You can't avoid roots and trigonometry here, so you will quickly run into irrational and transcendental numbers. Same for finance, where you will encounter logarithms at some point.</p>
<p>Here, you have two choices: turn your language into a CAS (with all the complexity that carries) or punt to some sort of inexact type. In the latter case, I would <em>still</em> argue it should be base-10, and possibly also bigger than just 64 bit.</p>
<p>One idea might be to keep function applications around as un-evaluated expressions. For example, if you encounter <code>a := sqrt(2)</code>, instead of evaluating it and having to punt to an inexact type, you keep it around as an un-evaluated expression. Then, when you later encounter <code>a**2</code>, you can cancel out the two operations and end up with a genuine <code>2</code> instead of something that is close to, but not equal to <code>2</code>.</p>
<p>The problem with such representations is that they are essentially <em>programs</em>. With all the consequences. It doesn't take much and all of a sudden, simply checking whether two numbers are equal requires checking whether two programs compute the same function, which in the general case is equivalent to solving the Halting Problem. You end up with a number representation where your numbers are super-precise and super-accurate, but you cannot even tell whether they are equal.</p>
<p>There are also things like <a href="https://iquilezles.org/articles/floatingbar/" rel="noreferrer">floating bar</a> or <a href="https://wikipedia.org/wiki/Interval_arithmetic" rel="noreferrer">interval arithmetic</a>.</p>
<p>For an example of a language that cares a lot about accurate and precise numbers, take a look at <a href="https://frinklang.org/#NumericTypes" rel="noreferrer">Frink</a>.</p>
<p>In conclusion, I would say there should be a <em>default</em> type that is useful for a lot of real-world cases. It should be <em>decimal</em>, have <em>arbitrary precision</em>, and support at least <em>rational</em> numbers. (Of course, the in-memory representation can be optimized as required.) For operations that are not closed under the rationals, there should be alternatives with easy conversions all around.</p>

CC BY-SA 4.0
2023-07-01T08:49:12.857Z
2023-07-01T08:49:12.857Z
Jörg W Mittag
CC BY-SA 4.0
2023-07-01T09:03:03.020Z
How should "be decimal" and "support at least rational numbers" be reconciled? You mentioned 1/3 already - is the argument for that to be out of scope, or for numbers not to be representationally decimal, just syntactically decimal?
Michael Homer
<p>Floating point numbers can often have accuracy issues when a number is too small or too big, see <a href="https://stackoverflow.com/questions/73673517/simple-example-for-floating-point-accuracy">relevant stackoverflow</a>.</p>

CC BY-SA 4.0
2023-05-16T20:38:07.303Z
2023-05-16T20:38:07.303Z
kouta-kun
<h1>Conversions</h1>
<p>Ofttimes, you have a function that takes a float, but you only have integers. Especially with languages where number conversions are explicit, this can become quite verbose. For example, Kotlin has no power operator for <code>Int</code>s, just for <code>Double</code>s and <code>Float</code>s. I have written the following code at least three times by now:</p>
<pre><code>val x = y.toDouble().pow(z.toDouble()).toInt()
</code></pre>

CC BY-SA 4.0
2023-05-16T22:38:17.833Z
2023-05-16T22:38:17.833Z
Seggan
<blockquote>
<p>I know that having different ones can improve memory usage.</p>
</blockquote>
<p>It is possible to eat your cake and have it too. APL tends to expose a single number type, but internally use the most efficient internal representation available for the actual value.</p>

CC BY-SA 4.0
2023-05-16T20:34:10.680Z
2023-05-16T20:34:10.680Z
Adám
<p>It's not a common case, but integral data types (sometimes known as shorts and longs) allow for <a href="https://en.wikipedia.org/wiki/Integer_overflow" rel="noreferrer">integer overflow</a>, which may be used by clever programmers (if the programming language allows it). E.g. for an unsigned 8-bit integer type, with a range from 0 to 255, a programmer <em>may</em> use the fact that 255 + 1 = 0. Such use should be well-documented, and I can't remember the last time I've used it, but it's definitely possible and very difficult to support with floating point numbers.</p>

CC BY-SA 4.0
2023-05-16T19:45:52.960Z
2023-05-16T19:45:52.960Z
Glorfindel
CC BY-SA 4.0
2023-05-16T19:48:43.897Z
Python circumvents this by having what are sometimes called _bigints_ — dynamically-allocated integers with no hard limit — but that comes with its own set of drawbacks.
Bbrk24
# What are the downsides of having types for floats and integers?
Posted by: username_0 on 2023-05-16
What are the downsides to having different data types for floats and integers instead of just a number data type? I know that having different ones can improve memory usage. But are there any downsides other than some programmers using the language may not like it?

Credit to [Math Cat](https://area51.stackexchange.com/users/210228/mathcat) for [the original A51 question](https://area51.stackexchange.com/proposals/127456/programming-language-design-and-implementation/127718#127718)
**Tags:** language-design numbers
---
## 6 answers
### Answer by username_7 on 2023-05-16. Score: 6 | Accepted answer
It's not a common case, but integral data types (sometimes known as shorts and longs) allow for [integer overflow](https://en.wikipedia.org/wiki/Integer_overflow), which may be used by clever programmers (if the programming language allows it). E.g. for an unsigned 8-bit integer type, with a range from 0 to 255, a programmer *may* use the fact that 255 + 1 = 0. Such use should be well-documented, and I can't remember the last time I've used it, but it's definitely possible and very difficult to support with floating point numbers.
> **Comments:**
> **username_8** (2023-05-16): Python circumvents this by having what are sometimes called _bigints_ — dynamically-allocated integers with no hard limit — but that comes with its own set of drawbacks.  
---
### Answer by username_1 on 2023-05-16. Score: 6
The main advantage of having a number type is simplicity and ease of use. Many versions of BASIC just had floating point numbers, which reduced the size of the code (given that the first home computer, which Bill Gates wrote the BASIC for, had only 4K of memory, this was very important) and made it so that beginning programmers didn't have to learn the difference between integers and floats, everything just being numbers.

Code size is no longer an issue; few deal with systems with less than 1MB of memory. When writing a language for a beginning audience, especially children, I can still see the value in simplifying that detail.
---
### Answer by username_2 on 2023-07-01. Score: 5
The problem with having only a single number type is: *which number type do you pick*?

For a good example of what *not* to do, you have to look no further than the most widely-used (depending on definition) programming language, JavaScript. JavaScript had for a very long time only a single number type, a IEEE 754-2019 / ISO/IEC 60559:2020 *binary64* floating point number.

There are two problems with this. Everybody knows about the limitations of floating point with its fixed precision and accuracy, and that's what everybody is focusing on, but that's only half the story. There is another problem here: the fact that it is a *binary* representation.

For the majority of real-world problems, by which I mean the kinds of problems which casual programmers and business programmers encounter, we are dealing with *decimal* numbers. Whether that's money, distances, speeds, weights, areas, volumes, percentages, etc. And users have an intuition about those: they know that 1/3 cannot be represented in decimal, they know that π cannot be represented in any integer base, but they are *very surprised* by the fact that JavaScript cannot represent 0.1.

I would argue that a programming language that does not have a good reason to do so (e.g. a language specifically for cryptography) should choose base-10 as the default number representation. I would also argue that arbitrary precision decimal rationals are a better default type than either floats or integers. I.e. make `12.34` syntactic sugar for `1234/100` and `12.34%` syntactic sugar for `1234/100/100`.

Arbitrary precision decimal rationals will work as long as you restrict the operations to addition, subtraction, multiplication, and division, as well as exponentiation by a natural number. For most users, those should be enough. Heck, I would bet a good sum of money that a significant portion of users don't even know that an exponent can be negative or non-integer!

It gets more interesting when you get into geometry, though. You can't avoid roots and trigonometry here, so you will quickly run into irrational and transcendental numbers. Same for finance, where you will encounter logarithms at some point.

Here, you have two choices: turn your language into a CAS (with all the complexity that carries) or punt to some sort of inexact type. In the latter case, I would *still* argue it should be base-10, and possibly also bigger than just 64 bit.

One idea might be to keep function applications around as un-evaluated expressions. For example, if you encounter `a := sqrt(2)`, instead of evaluating it and having to punt to an inexact type, you keep it around as an un-evaluated expression. Then, when you later encounter `a**2`, you can cancel out the two operations and end up with a genuine `2` instead of something that is close to, but not equal to `2`.

The problem with such representations is that they are essentially *programs*. With all the consequences. It doesn't take much and all of a sudden, simply checking whether two numbers are equal requires checking whether two programs compute the same function, which in the general case is equivalent to solving the Halting Problem. You end up with a number representation where your numbers are super-precise and super-accurate, but you cannot even tell whether they are equal.

There are also things like [floating bar](https://iquilezles.org/articles/floatingbar/) or [interval arithmetic](https://wikipedia.org/wiki/Interval_arithmetic).

For an example of a language that cares a lot about accurate and precise numbers, take a look at [Frink](https://frinklang.org/#NumericTypes).

In conclusion, I would say there should be a *default* type that is useful for a lot of real-world cases. It should be *decimal*, have *arbitrary precision*, and support at least *rational* numbers. (Of course, the in-memory representation can be optimized as required.) For operations that are not closed under the rationals, there should be alternatives with easy conversions all around.
> **Comments:**
> **username_3** (2023-07-01): How should "be decimal" and "support at least rational numbers" be reconciled? You mentioned 1/3 already - is the argument for that to be out of scope, or for numbers not to be representationally decimal, just syntactically decimal?  
---
### Answer by username_4 on 2023-05-16. Score: 3
Floating point numbers can often have accuracy issues when a number is too small or too big, see [relevant stackoverflow](https://stackoverflow.com/questions/73673517/simple-example-for-floating-point-accuracy).
---
### Answer by username_5 on 2023-05-16. Score: 2
Conversions
Ofttimes, you have a function that takes a float, but you only have integers. Especially with languages where number conversions are explicit, this can become quite verbose. For example, Kotlin has no power operator for Ints, just for Doubles and Floats. I have written the following code at least three times by now:
val x = y.toDouble().pow(z.toDouble()).toInt()
---
### Answer by username_6 on 2023-05-16. Score: 2
> I know that having different ones can improve memory usage.

It is possible to eat your cake and have it too. APL tends to expose a single number type, but internally use the most efficient internal representation available for the actual value.
---
