# Another Arithemetic overflow problem

**URL:** <https://forum.crystal-lang.org/t/another-arithemetic-overflow-problem/2000>\
**Category:** Offtopic\
**Created:** [April 24, 2020, 10:55pm UTC](https://forum.crystal-lang.org/t/another-arithemetic-overflow-problem/2000 "2020-04-24T22:55:31Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![jzakiya](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jzakiya/32/278_2.png) [@jzakiya](https://forum.crystal-lang.org/u/jzakiya)\
**Post date:** [April 24, 2020, 10:55pm UTC](https://forum.crystal-lang.org/t/another-arithemetic-overflow-problem/2000/1 "2020-04-24T22:55:31Z")

</div>

In the code below you see I explicitly set the shown values to be `i64` 64-bit values.  
However, when it get close to the limit value, I notice some of them switching between `i32` and `i64` types. How can this happen? I set them to be (and always stay) `i64` to explicitly to prevent `overflow`.

```auto
start = Time.monotonic
print("The self-describing numbers are:")
i = 10i64 # self-describing number must end in 0
pw = 10i64 # power of 10
fd = 1i64 # first digit
sd = 1i64 # second digit
dg = 2i64 # number of digits
mx = 11i64 # maximum for current batch
lim = 9_100_000_001i64 # sum of digits can't be more than 10
while i < lim
  if selfDesc(i)
    secs = (Time.monotonic - start).total_seconds
    print("\n#{i} in #{secs} secs")
  end
  i += 10
  if i > mx
    fd += 1
    sd -= 1
    if sd >= 0
      i = fd * pw
    else
      pw *= 10
      dg += 1
      i = pw
      fd = 1
      sd = dg - 1
    end
    puts " i = #{i.class}, sd = #{sd.class}, pw = #{pw.class}, mx = #{mx.class}"
    mx = i + sd * pw // 10
  end
end

```

I inserted that `puts` statement line before the line: `mx = i + sd * pw // 10`  
because that’s where the error message said the over flow occurred.  
Here’s the output just before it fails.

```auto
 i = Int32, sd = Int64, pw = Int64, mx = Int32
 i = Int32, sd = Int64, pw = Int64, mx = Int32
 i = Int32, sd = Int64, pw = Int64, mx = Int32
 i = Int32, sd = Int64, pw = Int64, mx = Int32
 i = Int64, sd = Int64, pw = Int64, mx = Int32
 i = Int32, sd = Int64, pw = Int64, mx = Int64

```

I finally figured out how to “fix” it by making all the constants in that inner loop `i64`s.  
But why should I have to do this? Why do the number types change to lower types?

```auto
if i > mx
    fd += 1i64
    sd -= 1i64
    if sd >= 0
      i = fd * pw
    else
      pw *= 10i64
      dg += 1i64
      i = pw
      fd = 1i64
      sd = dg - 1i64
    end
    #puts " i = #{i.class}, sd = #{sd.class}, pw = #{pw.class}, mx = #{mx.class}"
    mx = i + sd * pw // 10

```

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [April 24, 2020, 11:12pm UTC](https://forum.crystal-lang.org/t/another-arithemetic-overflow-problem/2000/2 "2020-04-24T23:12:49Z")

</div>

There’s a `fd = 1` in the else branch. That assigns a number of value 1 to `fd` and since no type is specified, it picks the default type `Int32`. Just changing this line to `fd = 1i64` is necessary and fixes the problem.

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [April 24, 2020, 11:14pm UTC](https://forum.crystal-lang.org/t/another-arithemetic-overflow-problem/2000/3 "2020-04-24T23:14:05Z")

</div>

Btw. you can add type restrictions to local variables, that would have immediately alerted you about the mismatching type (ideally it could probably even autocast assigned literals to Int64).

---

<div class="post-metadata">

**Author:** ![jzakiya](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jzakiya/32/278_2.png) [@jzakiya](https://forum.crystal-lang.org/u/jzakiya)\
**Post date:** [April 24, 2020, 11:50pm UTC](https://forum.crystal-lang.org/t/another-arithemetic-overflow-problem/2000/4 "2020-04-24T23:50:13Z")

</div>

> [@straight-shoota](#):
>
> Btw. you can add type restrictions to local variables, that would have immediately alerted you about the mismatching type (ideally it could probably even autocast assigned literals to Int64).

How do you do that? Please give examples.

Changing the `fd = 1` to `fd = i64` did work.  
However, what I ended up doing is changing the order of multiplication, shown below, to have `pw` set the type precedence for the multiplication on that line, so `fd = 1` now works.

```auto
if i > mx
    fd += 1
    sd -= 1
    if sd >= 0
      i = pw * fd <- pw always i64, sets * type precedence
      #i = fd * pw
    else
      pw *= 10
      dg += 1
      i = pw
      fd = 1 <- can remain the same 
      sd = dg - 1
    end
    #puts " i = #{i.class}, sd = #{sd.class}, pw = #{pw.class}, mx = #{mx.class}"
    mx = i + sd * pw // 10
  end

```

There’s needs to be a clear (and documented) way users can set variable types and know all math operations results will produce values of that type.

I was lucky here because I’ve run into this kind of thing enough now to know what to look to change, but I pity the poor soul who has no idea of what’s going on, let alone how to figure out how to fix it. 😡

---

<div class="post-metadata">

**Author:** ![mavu](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/mavu/32/213_2.png) [@mavu](https://forum.crystal-lang.org/u/mavu)\
**Post date:** [April 25, 2020, 7:36am UTC](https://forum.crystal-lang.org/t/another-arithemetic-overflow-problem/2000/5 "2020-04-25T07:36:25Z")

</div>

**NEVER DO THIS**

it’s in the documentation under [https://crystal-lang.org/reference/syntax\_and\_semantics/type\_grammar.html](https://crystal-lang.org/reference/syntax_and_semantics/type_grammar.html) then “declaring variables”

```auto
x = uninitialized Int32

x = 0
puts x

x = "test"
puts x

```

this produces :

```auto
 Showing last frame. Use --error-trace for full trace.

In test.cr:8:1

 8 | x = "test"
     ^
Error: type must be Int32, not (Int32 | String)

```

not sure if there is a different/better way.

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [April 25, 2020, 11:44am UTC](https://forum.crystal-lang.org/t/another-arithemetic-overflow-problem/2000/6 "2020-04-25T11:44:08Z")

</div>

No, please don’t use `uninitialized`. That’s unsafe!!

The way to declare the type of a variable is the same as you declare the type of anything:

```crystal
x : Int64 = 1
# do stuff with x

```

tl;dr: **never, ever** use `uninitialize`

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [April 25, 2020, 11:54am UTC](https://forum.crystal-lang.org/t/another-arithemetic-overflow-problem/2000/7 "2020-04-25T11:54:28Z")

</div>

> [@jzakiya](#):
>
> There’s needs to be a clear (and documented) way users can set variable types and know all math operations results will produce values of that type.

I see that documentation on type restrictions is missing from the reference page on [local variables](https://crystal-lang.org/reference/syntax_and_semantics/local_variables.html). We’ll need to add that.

The result type of math operations doesn’t depend on the type restriction of the variable they are assigned to. It only depends on the return type of the methods that implements it. And this is actually well documented. For example the API docs for [`Int32#*(other : Int64) : Int32`](https://crystal-lang.org/api/0.34.0/Int32.html#*(other:Int64):self-instance-method). Per convention, binary operators usually return the type of the first operand (see [Operators - Crystal](https://crystal-lang.org/reference/syntax_and_semantics/operators.html#binary-operators)).

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [April 25, 2020, 12:05pm UTC](https://forum.crystal-lang.org/t/another-arithemetic-overflow-problem/2000/8 "2020-04-25T12:05:18Z")

</div>

> There’s needs to be a clear (and documented) way users can set variable types and know all math operations results will produce values of that type.

As straigh-shoota said, the type of `a op b` is always `a`. I think that’s a pretty easy thing to remember.

> I was lucky here because I’ve run into this kind of thing enough now to know what to look to change, but I pity the poor soul who has no idea of what’s going on, let alone how to figure out how to fix it.

We are aware of the problem. Do you have ideas on how to improve the situation?

---

<div class="post-metadata">

**Author:** ![rogerdpack](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/rogerdpack/32/117_2.png) [@rogerdpack](https://forum.crystal-lang.org/u/rogerdpack)\
**Post date:** [April 26, 2020, 1:53am UTC](https://forum.crystal-lang.org/t/another-arithemetic-overflow-problem/2000/9 "2020-04-26T01:53:28Z")

</div>

See also [https://github.com/crystal-lang/crystal/issues/8872](https://github.com/crystal-lang/crystal/issues/8872) (though not quite the same thing…)

---

<div class="post-metadata">

**Author:** ![jhass](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jhass/32/1779_2.png) [@jhass](https://forum.crystal-lang.org/u/jhass)\
**Post date:** [April 26, 2020, 2:33pm UTC](https://forum.crystal-lang.org/t/another-arithemetic-overflow-problem/2000/10 "2020-04-26T14:33:21Z")

</div>

4 posts were split to a new topic: [Arithmethic overflow should not raise an exception](https://forum.crystal-lang.org/t/arithmethic-overflow-should-not-raise-an-exception/2006)

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [April 26, 2020, 9:44pm UTC](https://forum.crystal-lang.org/t/another-arithemetic-overflow-problem/2000/11 "2020-04-26T21:44:10Z")

</div>

What if we automatically turn `Int32 | Int64` into Int64? That is, you can’t really have a union of two integer types when one fits perfectly inside another one: you just get the bigger type. Same if you do `Int8 | Int16`, `UInt32 | UInt64`, etc. Then at least when mixing Int64 code with Int32 you’ll always get Int64, so correct code.

I’m going to try this next.

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [April 26, 2020, 10:23pm UTC](https://forum.crystal-lang.org/t/another-arithemetic-overflow-problem/2000/12 "2020-04-26T22:23:42Z")

</div>

Meh, maybe for 2.0. Until 1.0 I won’t experiment any more.

---

<div class="post-metadata">

**Author:** ![jzakiya](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jzakiya/32/278_2.png) [@jzakiya](https://forum.crystal-lang.org/u/jzakiya)\
**Post date:** [April 26, 2020, 11:28pm UTC](https://forum.crystal-lang.org/t/another-arithemetic-overflow-problem/2000/13 "2020-04-26T23:28:29Z")

</div>

This may seem a naive question, but do you understand what `Go` is doing to be able to run the equivalent code with no extra `type` value declarations? Understanding first how it (et al) deal with this issue (design choices) may provide better clarity to go forward from.

```auto
package main
 
import (
    "fmt"
    "strconv"
    "strings"
    "time"
)
 
func selfDesc(n uint64) bool {
    if n >= 1e10 {
        return false
    }
    s := strconv.FormatUint(n, 10)
    for d, p := range s {
        if int(p)-'0' != strings.Count(s, strconv.Itoa(d)) {
            return false
        }
    }
    return true
}
 
func main() {
    start := time.Now()
    fmt.Println("The self-describing numbers are:")
    i := uint64(10) // self-describing number must end in 0
    pw := uint64(10) // power of 10
    fd := uint64(1) // first digit
    sd := uint64(1) // second digit
    dg := uint64(2) // number of digits
    mx := uint64(11) // maximum for current batch
    lim := uint64(9_100_000_001) // sum of digits can't be more than 10
    for i < lim {
        if selfDesc(i) {
            secs := time.Since(start).Seconds()
            fmt.Printf("%d (in %.1f secs)\n", i, secs)
        }
        i += 10
        if i > mx {
            fd++
            sd--
            if sd >= 0 {
                i = fd * pw
            } else {
                pw *= 10
                dg++
                i = pw
                fd = 1
                sd = dg - 1
            }
            mx = i + sd*pw/10
        }
    }
    osecs := time.Since(start).Seconds()
    fmt.Printf("\nTook %.1f secs overall\n", osecs)
}

```

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [April 26, 2020, 11:44pm UTC](https://forum.crystal-lang.org/t/another-arithemetic-overflow-problem/2000/14 "2020-04-26T23:44:14Z")

</div>

Go has no union types.

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [April 26, 2020, 11:50pm UTC](https://forum.crystal-lang.org/t/another-arithemetic-overflow-problem/2000/15 "2020-04-26T23:50:15Z")

</div>

As far as I know Golang doesn’t allow to change the type of a variable. So when you assign an untyped number literal `1` to a local variable, it seems to be autocased to the type of the varible.

```auto
fd := uint64(1)
fd = 1
fmt.Println(reflect.TypeOf(fd)) // => uint64
fd = uint(32) // cannot use uint32(1) (type uint32) as type uint64 in assignment

```

---

<div class="post-metadata">

**Author:** ![jzakiya](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jzakiya/32/278_2.png) [@jzakiya](https://forum.crystal-lang.org/u/jzakiya)\
**Post date:** [April 27, 2020, 12:33am UTC](https://forum.crystal-lang.org/t/another-arithemetic-overflow-problem/2000/16 "2020-04-27T00:33:21Z")

</div>

Is autocasting something that you can do too when appropriate, to use the larger type?
