<p>The fact that a variable - call it <span class="math-container">$N_i$</span> - defined as 'number of universities in a state divided by population of state' takes very small values should not be a problem. It will mean that the absolute differences in values between states will be very small, but that does not matter.  What matters for a regression are the <em>proportional</em> differences in values.  Suppose for example that for two states <span class="math-container">$j$</span> and <span class="math-container">$k$</span>, <span class="math-container">$N_j=0.0000010$</span> and <span class="math-container">$N_k=0.0000012$</span>. Then <span class="math-container">$N_k$</span> is 20% larger than <span class="math-container">$N_j$</span>. If instead you adopted Henry's suggestion, so that the values became <span class="math-container">$1.0$</span> and <span class="math-container">$1.2$</span>, the proportional difference would still be 20%.</p>
<p>Suppose now that you estimate a regression equation:</p>
<p><span class="math-container">$$N_i = \beta_0 + \beta_1 E_i + \epsilon_i$$</span></p>
<p>where <span class="math-container">$E_i$</span> is an economic index, the <span class="math-container">$\beta$</span>'s are parameters to be estimated, and <span class="math-container">$\epsilon_i$</span> is the error term. (I'm assuming here that <span class="math-container">$N_i$</span> is taken to be the dependent variable.) The small values of the <span class="math-container">$N_i$</span> won't prevent you from running such a regression.  They will just mean that the <span class="math-container">$\beta$</span>'s will also be small (though how small will also depend on the values of <span class="math-container">$E_i$</span>).  As ever with regressions, further questions will be whether the estimated value of <span class="math-container">$\beta_1$</span> is significantly different from zero, and if so whether the estimated relationship can properly be given a causal interpretation.</p>

CC BY-SA 4.0
2022-08-16T11:46:36.637Z
While there is no issue theoretically, I think in practice rounding problems might occur with such small numbers - think about numerical matrix inversion.
BrsG
CC BY-SA 4.0
2022-08-16T12:13:32.507Z
@BrsG  Agreed, this could be a problem with particular regression software depending on thr point at which it rounded small values.
Adam Bailey
CC BY-SA 4.0
2022-08-16T11:22:40.350Z
2022-08-16T11:22:40.350Z
Adam Bailey
<p>Theoretically it does not matter as @Adam Bailey showed (as long as you ignore computer theory).</p>
<p>Realistically, it matters quite a bit for at least two reasons:</p>
<ul>
<li><p>how do you interpret your coefficient? As a human being, do you prefer to hear that there are 1.2 Universities per 1 Million inhabitants in a city, or do you find  0.000001 per person easier to graps? Personally, I find the the latter rather dismal. Most of the times (for example google <a href="https://www.google.com/search?q=hospital+beds+per+capita" rel="nofollow noreferrer">hospital beds per capita</a>), the reported values will be scaled to something that humans can grasp.</p>
</li>
<li><p>As @BrsG noted, computers may be your enemy here. They predominantly use floating point math (and if you deal with large numbers, integer arithemtic will also bite you). This may be a bit esoteric without examples but can be quickly shown with code. I answered a question asking if the <a href="https://quant.stackexchange.com/a/63891/54838">&quot;future value function is broken&quot;</a> some time ago which is related to this. It is probably better to use an actual regression example though.</p>
</li>
</ul>
<p>I will use the simplest possible and just copy paste from Wikipedia's OLS <a href="https://en.wikipedia.org/wiki/Ordinary_least_squares#Example_with_real_data" rel="nofollow noreferrer">example</a>. One may think OLS will be OLS, no matter what implementation or language you use but that is not generally true. Least squares estimates satisfy the condition that the residual is orthogonal to the columns of <span class="math-container">$\mathbf{X}$</span>.
<span class="math-container">$$
\mathbf{X^\prime (y - X\widehat{\beta})} = \mathbf{0}
$$</span>
which can be re-written as
<span class="math-container">$$
\mathbf{X^\prime X}\widehat{\mathbf{\beta}}=\mathbf{X^\prime y}
$$</span>
Solving for <span class="math-container">$\beta$</span> provides the standard text book formulas for least squares estimate calculated as
<span class="math-container">$$
\widehat{\mathbf{\beta}}=\mathbf{X^\prime X}^{-1}\mathbf{X^\prime y}.
$$</span>
<br></p>
<p>I decided to use <a href="https://julialang.org/" rel="nofollow noreferrer">Julia</a> because its a very flexible language that is intuitive to read, even if you are not familiar with the language itself.</p>
<pre><code># manually create the data from the Wikipedia example 
using DataFrames, GLM, LinearAlgebra
height = [1.47,1.50,1.52,1.55,1.57,1.60,1.63,1.65,1.68,1.70,1.73,1.75,1.78,1.80,1.83]
weight = [52.21,53.12,54.48,55.84,57.20,58.57,59.93,61.29,63.11,64.47,66.28,68.10,69.92,72.19,74.46]

data = DataFrame(weight=weight,height=height, height2 = height.^2)
</code></pre>
<p><a href="https://i.sstatic.net/bqpuZ.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/bqpuZ.png" alt="enter image description here" /></a></p>
<p>The simple Wiki example is like this:
<a href="https://i.sstatic.net/H0omM.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/H0omM.png" alt="enter image description here" /></a></p>
<p><br><br>
If you dont want a package but prefer the good old manual way, you could use several procedures. The usual way to define a &quot;division&quot; operation for matrices is to define <span class="math-container">$A / B =  ^{−1}$</span>, where  <span class="math-container">$^{−1}$</span>  denotes the inverse of B. Because matrix multiplication is not commutative, one can also define a left division or so-called backslash-division as <span class="math-container">$A \backslash B =  ^{−1}$</span>. <a href="https://en.wikipedia.org/wiki/Moore%E2%80%93Penrose_inverse#Linearly_independent_columns" rel="nofollow noreferrer">Moore Penrose Inverse</a> is just Julia's <code>pinv(X)</code>. Basically, OLS is solving <code>Ax=b</code> where you add a column of <code>1s</code> if you want an intercept, so <a href="https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#man-linalg-factorizations" rel="nofollow noreferrer">matrix decompositions</a>.   (a.k.a. matrix factorizations) of <code>A\b</code> is OLS. That's why the examples below define <code>X</code> to contain a vector of ones for the intercept, and computes the regression result as <code>X\weight</code>.</p>
<pre><code>len = length(&quot;Normal Equation result 1&quot;)
println(len)
X= [ones(15) height height2] # adding the intercept

#b = (x'x)\x'y
println(lpad(&quot;Normal Equation result 1&quot;,len) *&quot;$((X'X)^-1*X'*weight)&quot;) # using “normal equations” approach

# which is the following
println(lpad(&quot;Normal Equation result 2&quot;,len) *&quot;$(inv(transpose(X)*X)*transpose(X)*weight)&quot; )

β = X \ weight # Uses QR decomposition
println(lpad(&quot;QR result&quot;,len) *&quot;$β&quot;)

β = pinv(X) * weight # uses SVG 
println(lpad(&quot;SVD result&quot;,len) *&quot;$β&quot;)

β = cholesky(Hermitian(X'X))\(X'weight) # Cholesky decomposition
println(lpad(&quot;Cholesky result&quot;,len) *&quot;<span class="math-container">$β")
 #println("$</span>(lpad(T,7)):&quot;)
</code></pre>
<p><a href="https://i.sstatic.net/bNU4m.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/bNU4m.png" alt="enter image description here" /></a></p>
<p>So far so good and just what Wikipedia computes as well. Now suppose we measure height in cm (*100).</p>
<p><a href="https://i.sstatic.net/mujoO.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/mujoO.png" alt="enter image description here" /></a>
<a href="https://i.sstatic.net/MyNKf.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/MyNKf.png" alt="enter image description here" /></a></p>
<p>Still working well and as expected just <span class="math-container">$/100$</span> and <span class="math-container">$/100^2$</span> respectively.</p>
<p><strong>Here is the problem</strong></p>
<ul>
<li>If we get a bit fancier, and use <a href="https://www.google.com/search?q=meter+to+nanometer&amp;rlz=1" rel="nofollow noreferrer">nanometers</a>, we get</li>
</ul>
<p><a href="https://i.sstatic.net/Ueo8E.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/Ueo8E.png" alt="enter image description here" /></a>
<a href="https://i.sstatic.net/dJ2rR.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/dJ2rR.png" alt="enter image description here" /></a></p>
<p>Now, this does not look very good anymore. The official package shows everything as zero and struggles with SE and confidence intervals. QR and SVD clearly start to deteriorate and essentially you may be scratching your head if the results make sense.</p>
<ul>
<li>What definitely does not make sense is to have <a href="https://stats.stackexchange.com/a/221930/322254">perfect multicollinearity</a>. This is easy to show if we use height and height*2 (similar to the example in cross validated that I linked).
<a href="https://i.sstatic.net/UFrMa.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/UFrMa.png" alt="enter image description here" /></a></li>
</ul>
<p><a href="https://i.sstatic.net/ohJvf.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/ohJvf.png" alt="enter image description here" /></a>
The official package is not exactly great in telling you that you cannot invert this matrix and simply excludes one of the two in computing by default. To be fair, the documentation is pretty clear about this though and if you include <code>dropcollinear=false</code> you get the warning that the matrix is not positive definite and that the Cholesky factorization failed. On the other hand, the manual formulas are giving you very explicit warnings. However, this only works if there is perfect multicollinearity (at machine precision).</p>
<p>Using the same logic, but making height2 very small (I chose ./100000000000000), you will see the following!</p>
<p><a href="https://i.sstatic.net/ftDF1.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/ftDF1.png" alt="enter image description here" /></a>
<a href="https://i.sstatic.net/xGokh.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/xGokh.png" alt="enter image description here" /></a></p>
<p>BANG! Completely different values depending on the implementation, but all provide a value despite there being perfect multicollinearity.</p>
<p><strong>Explanation</strong>:</p>
<p>Floating-Point representation is by far the most common way of representing real numbers in computing. However, squeezing infinitely many <a href="https://en.wikipedia.org/wiki/Real_number" rel="nofollow noreferrer">real numbers</a> into a finite number of bits requires an approximate representation because most calculations with real numbers will produce quantities that cannot be exactly represented.</p>
<p>The distance between two adjacent representable floating-point numbers is called <code>machine epsilon</code>.This distance is not constant, and the representable floating-point numbers are densest in the real number line near zero, and grow sparser exponentially as one moves farther away from zero.</p>
<pre><code>theme(:juno)
range = -10.0^4:1:10.0^4
plot(range, [eps(i) for i in range],  legend = false, title =  &quot;Machine epsilon for various values&quot;)
yaxis!(&quot;Machine Epsilon&quot;)
xaxis!(&quot;Values&quot;)
</code></pre>
<p><a href="https://i.sstatic.net/C4Amx.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/C4Amx.png" alt="enter image description here" /></a></p>
<p>With large values (especially integers) you have a problem with overflow, which occurs when an arithmetic operation attempts to create a numeric value that is outside of the range that can be represented with a given number of digits – either higher than the maximum or lower than the minimum representable value. The most common result of an overflow is to wrap around the maximum. Computer arithmetic of integers is implemented that way. You can read some more <a href="https://quant.stackexchange.com/a/63891/54838">here</a>. This may sound crazy, but is exactly how car odometers worked, except that signed integers display negative values as well. It is also how the 12-hour clock works which wraps around every 12 hours (if it is 6:00 right now, 9 hours later it will be 3:00 and not 6+9 = 15).</p>
<p>Also, floating-point operations are not associative.</p>
<p><a href="https://i.sstatic.net/gnfBG.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/gnfBG.png" alt="enter image description here" /></a></p>
<p>This <a href="https://discourse.julialang.org/t/array-ordering-and-naive-summation/1929" rel="nofollow noreferrer">post</a> by Stefan Karpinski about array ordering and floating point math not being associative illustrates this very well. He wrote the below function to check how many different sums you can get by reordering a set of floating-point numbers. He defines a function called sumsto which is always returning the exact same 2046 floating-point numbers but returns them in a different order based on x. My version is slightly modified from the original code to suit the newer Julia version I am using.</p>
<pre><code>realmax = reinterpret(Float64, reinterpret(UInt64, Inf)-1)
function sumsto(x::Float64)
    0 &lt;= x &lt; exp2(970) || throw(ArgumentError(&quot;sum must be in [0,2^970)&quot;))
    n, p₀ = Base.decompose(x) # integers such that `n*exp2(p₀) == x`
    [realmax; [exp2(p) for p in -1074:969 if iseven(n &gt;&gt; (p-p₀))]
    -realmax; [exp2(p) for p in -1074:969 if isodd(n &gt;&gt; (p-p₀))]]
end
</code></pre>
<p>If you check out the same function with less values, say 13, you can see the pattern.
<a href="https://i.sstatic.net/RZcVs.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/RZcVs.png" alt="enter image description here" /></a>
<a href="https://i.sstatic.net/bHVxB.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/bHVxB.png" alt="enter image description here" /></a></p>
<pre><code>x = 0.0
println(&quot;For <span class="math-container">$x the result is $</span>(foldl(+, sumsto(x)))&quot;)
println(&quot;For <span class="math-container">$x the result is $</span>(foldl(+, sumsto(eps(x))))&quot;)
x = 1.23
println(&quot;For <span class="math-container">$x the result is $</span>(foldl(+, sumsto(x)))&quot;)
x = ℯ
println(&quot;For <span class="math-container">$x the result is $</span>(foldl(+, sumsto(x+0)))&quot;)
x=π 
println(&quot;For <span class="math-container">$x the result is $</span>(foldl(+, sumsto(x+0)))&quot;)
x = 6.0221409e23
println(&quot;For <span class="math-container">$x the result is $</span>(foldl(+, sumsto(x)))&quot;)
x = 9.979201547673598e291
println(&quot;For <span class="math-container">$x the result is $</span>(foldl(+, sumsto(x)))&quot;)
</code></pre>
<p><a href="https://i.sstatic.net/urJXi.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/urJXi.png" alt="enter image description here" /></a></p>
<p>For any 64-bit float value of x from 0 up to (but not including) 2^970, the naive left-to-right sum of the vector returned by sumsto(x) is precisely x. To show it is not just some vodoo, I use the left-to-right sum with &quot;normal&quot; values. It clearly works here, but even with the 13 element vector from above, it produces the value 0.0 (although it is not always exact to the decimal in this case).</p>
<p><a href="https://i.sstatic.net/qIeJw.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/qIeJw.png" alt="enter image description here" /></a></p>
<p><strong>Summary</strong></p>
<p>Long story short, I do not recommend to use very off the scale variables, especially if mixed together. The way computers operate is not very favourable in these cases.</p>
<p>Moreover, intuitively it makes more sense to me to <a href="https://en.wikipedia.org/wiki/List_of_countries_by_hospital_beds" rel="nofollow noreferrer">read</a> there are ~10 ICU beds per 100,000 as opposed to comparing 0.000083 beds per capita in Russia vs 0.0003870 in Germany.</p>

CC BY-SA 4.0
2022-08-18T23:17:10.760Z
2022-08-20T10:09:58.587Z
2022-08-20T10:09:58.587Z
AKdemy
<p>I am currently interested in looking at the relationship between the number of universities in a state and an economic index by state. It occurs to me though that the number of colleges in a state may be correlated with population. After investigating the correlation, it was found to be 0.82.</p>
<p>If I divide the number of colleges by population in that state, my concern is if it make sense for interpretation. Every value for this newly constructed variable is roughly 0.000001. Is there another method I should consider for normalizing for population?</p>

CC BY-SA 4.0
2022-08-14T00:08:35.217Z
You could rescale to colleges per million population which might make the numbers about 1
Henry
CC BY-SA 4.0
2022-08-15T20:36:27.127Z
"Every value for this newly constructed variable is roughly 0.000001."  Why do you perceive this as a problem?  Is it a) because the values are very small, or b) because the values are approximately equal?
Adam Bailey
CC BY-SA 4.0
2022-08-15T20:46:19.510Z
It is mainly for making scatterplots and eventually running regressions. That is the only reason I am wondering if it is a problem, the fact that the numbers are so small for interpretation.
Mark Lee
<econometrics>
Normalizing for Population in Regression
Mark Lee
# Normalizing for Population in Regression

(Asked by: username_0 on 2022-08-13)

I am currently interested in looking at the relationship between the number of universities in a state and an economic index by state. It occurs to me though that the number of colleges in a state may be correlated with population. After investigating the correlation, it was found to be 0.82.

If I divide the number of colleges by population in that state, my concern is if it make sense for interpretation. Every value for this newly constructed variable is roughly 0.000001. Is there another method I should consider for normalizing for population?

**Tags:** econometrics

> **Comments:**
> **username_1**: You could rescale to colleges per million population which might make the numbers about 1  
> **username_2**: "Every value for this newly constructed variable is roughly 0.000001."  Why do you perceive this as a problem?  Is it a) because the values are very small, or b) because the values are approximately equal?  
> **username_0**: It is mainly for making scatterplots and eventually running regressions. That is the only reason I am wondering if it is a problem, the fact that the numbers are so small for interpretation.  

---

## 2 answers

### Answer by username_2 on 2022-08-16. Score: 3

The fact that a variable - call it $N\_i$ - defined as 'number of universities in a state divided by population of state' takes very small values should not be a problem. It will mean that the absolute differences in values between states will be very small, but that does not matter. What matters for a regression are the *proportional* differences in values. Suppose for example that for two states $j$ and $k$, $N\_j=0.0000010$ and $N\_k=0.0000012$. Then $N\_k$ is 20% larger than $N\_j$. If instead you adopted username_1's suggestion, so that the values became $1.0$ and $1.2$, the proportional difference would still be 20%.

Suppose now that you estimate a regression equation:

$$N\_i = \beta\_0 + \beta\_1 E\_i + \epsilon\_i$$

where $E\_i$ is an economic index, the $\beta$'s are parameters to be estimated, and $\epsilon\_i$ is the error term. (I'm assuming here that $N\_i$ is taken to be the dependent variable.) The small values of the $N\_i$ won't prevent you from running such a regression. They will just mean that the $\beta$'s will also be small (though how small will also depend on the values of $E\_i$). As ever with regressions, further questions will be whether the estimated value of $\beta\_1$ is significantly different from zero, and if so whether the estimated relationship can properly be given a causal interpretation.

> **Comments:**
> **username_3**: While there is no issue theoretically, I think in practice rounding problems might occur with such small numbers - think about numerical matrix inversion.  
> **username_2**: @username_3  Agreed, this could be a problem with particular regression software depending on thr point at which it rounded small values.  

---

### Answer by username_4 on 2022-08-18. Score: 2

Theoretically it does not matter as @username_2 showed (as long as you ignore computer theory).
Realistically, it matters quite a bit for at least two reasons:

how do you interpret your coefficient? As a human being, do you prefer to hear that there are 1.2 Universities per 1 Million inhabitants in a city, or do you find  0.000001 per person easier to graps? Personally, I find the the latter rather dismal. Most of the times (for example google hospital beds per capita), the reported values will be scaled to something that humans can grasp.

As @username_3 noted, computers may be your enemy here. They predominantly use floating point math (and if you deal with large numbers, integer arithemtic will also bite you). This may be a bit esoteric without examples but can be quickly shown with code. I answered a question asking if the "future value function is broken" some time ago which is related to this. It is probably better to use an actual regression example though.


I will use the simplest possible and just copy paste from Wikipedia's OLS example. One may think OLS will be OLS, no matter what implementation or language you use but that is not generally true. Least squares estimates satisfy the condition that the residual is orthogonal to the columns of $\mathbf{X}$.
$$
\mathbf{X^\prime (y - X\widehat{\beta})} = \mathbf{0}
$$
which can be re-written as
$$
\mathbf{X^\prime X}\widehat{\mathbf{\beta}}=\mathbf{X^\prime y}
$$
Solving for $\beta$ provides the standard text book formulas for least squares estimate calculated as
$$
\widehat{\mathbf{\beta}}=\mathbf{X^\prime X}^{-1}\mathbf{X^\prime y}.
$$

I decided to use Julia because its a very flexible language that is intuitive to read, even if you are not familiar with the language itself.
# manually create the data from the Wikipedia example 
using DataFrames, GLM, LinearAlgebra
height = [1.47,1.50,1.52,1.55,1.57,1.60,1.63,1.65,1.68,1.70,1.73,1.75,1.78,1.80,1.83]
weight = [52.21,53.12,54.48,55.84,57.20,58.57,59.93,61.29,63.11,64.47,66.28,68.10,69.92,72.19,74.46]

data = DataFrame(weight=weight,height=height, height2 = height.^2)


The simple Wiki example is like this:


If you dont want a package but prefer the good old manual way, you could use several procedures. The usual way to define a "division" operation for matrices is to define $A / B =  ^{−1}$, where  $^{−1}$  denotes the inverse of B. Because matrix multiplication is not commutative, one can also define a left division or so-called backslash-division as $A \backslash B =  ^{−1}$. Moore Penrose Inverse is just Julia's pinv(X). Basically, OLS is solving Ax=b where you add a column of 1s if you want an intercept, so matrix decompositions.   (a.k.a. matrix factorizations) of A\b is OLS. That's why the examples below define X to contain a vector of ones for the intercept, and computes the regression result as X\weight.
len = length("Normal Equation result 1")
println(len)
X= [ones(15) height height2] # adding the intercept

#b = (x'x)\x'y
println(lpad("Normal Equation result 1",len) *"$((X'X)^-1*X'*weight)") # using “normal equations” approach

# which is the following
println(lpad("Normal Equation result 2",len) *"$(inv(transpose(X)*X)*transpose(X)*weight)" )

β = X \ weight # Uses QR decomposition
println(lpad("QR result",len) *"$β")

β = pinv(X) * weight # uses SVG 
println(lpad("SVD result",len) *"$β")

β = cholesky(Hermitian(X'X))\(X'weight) # Cholesky decomposition
println(lpad("Cholesky result",len) *"$β")
 #println("$(lpad(T,7)):")


So far so good and just what Wikipedia computes as well. Now suppose we measure height in cm (*100).


Still working well and as expected just $/100$ and $/100^2$ respectively.
Here is the problem

If we get a bit fancier, and use nanometers, we get



Now, this does not look very good anymore. The official package shows everything as zero and struggles with SE and confidence intervals. QR and SVD clearly start to deteriorate and essentially you may be scratching your head if the results make sense.

What definitely does not make sense is to have perfect multicollinearity. This is easy to show if we use height and height*2 (similar to the example in cross validated that I linked).



The official package is not exactly great in telling you that you cannot invert this matrix and simply excludes one of the two in computing by default. To be fair, the documentation is pretty clear about this though and if you include dropcollinear=false you get the warning that the matrix is not positive definite and that the Cholesky factorization failed. On the other hand, the manual formulas are giving you very explicit warnings. However, this only works if there is perfect multicollinearity (at machine precision).
Using the same logic, but making height2 very small (I chose ./100000000000000), you will see the following!


BANG! Completely different values depending on the implementation, but all provide a value despite there being perfect multicollinearity.
Explanation:
Floating-Point representation is by far the most common way of representing real numbers in computing. However, squeezing infinitely many real numbers into a finite number of bits requires an approximate representation because most calculations with real numbers will produce quantities that cannot be exactly represented.
The distance between two adjacent representable floating-point numbers is called machine epsilon.This distance is not constant, and the representable floating-point numbers are densest in the real number line near zero, and grow sparser exponentially as one moves farther away from zero.
theme(:juno)
range = -10.0^4:1:10.0^4
plot(range, [eps(i) for i in range],  legend = false, title =  "Machine epsilon for various values")
yaxis!("Machine Epsilon")
xaxis!("Values")


With large values (especially integers) you have a problem with overflow, which occurs when an arithmetic operation attempts to create a numeric value that is outside of the range that can be represented with a given number of digits – either higher than the maximum or lower than the minimum representable value. The most common result of an overflow is to wrap around the maximum. Computer arithmetic of integers is implemented that way. You can read some more here. This may sound crazy, but is exactly how car odometers worked, except that signed integers display negative values as well. It is also how the 12-hour clock works which wraps around every 12 hours (if it is 6:00 right now, 9 hours later it will be 3:00 and not 6+9 = 15).
Also, floating-point operations are not associative.

This post by Stefan Karpinski about array ordering and floating point math not being associative illustrates this very well. He wrote the below function to check how many different sums you can get by reordering a set of floating-point numbers. He defines a function called sumsto which is always returning the exact same 2046 floating-point numbers but returns them in a different order based on x. My version is slightly modified from the original code to suit the newer Julia version I am using.
realmax = reinterpret(Float64, reinterpret(UInt64, Inf)-1)
function sumsto(x::Float64)
    0 <= x < exp2(970) || throw(ArgumentError("sum must be in [0,2^970)"))
    n, p₀ = Base.decompose(x) # integers such that `n*exp2(p₀) == x`
    [realmax; [exp2(p) for p in -1074:969 if iseven(n >> (p-p₀))]
    -realmax; [exp2(p) for p in -1074:969 if isodd(n >> (p-p₀))]]
end

If you check out the same function with less values, say 13, you can see the pattern.


x = 0.0
println("For $x the result is $(foldl(+, sumsto(x)))")
println("For $x the result is $(foldl(+, sumsto(eps(x))))")
x = 1.23
println("For $x the result is $(foldl(+, sumsto(x)))")
x = ℯ
println("For $x the result is $(foldl(+, sumsto(x+0)))")
x=π 
println("For $x the result is $(foldl(+, sumsto(x+0)))")
x = 6.0221409e23
println("For $x the result is $(foldl(+, sumsto(x)))")
x = 9.979201547673598e291
println("For $x the result is $(foldl(+, sumsto(x)))")


For any 64-bit float value of x from 0 up to (but not including) 2^970, the naive left-to-right sum of the vector returned by sumsto(x) is precisely x. To show it is not just some vodoo, I use the left-to-right sum with "normal" values. It clearly works here, but even with the 13 element vector from above, it produces the value 0.0 (although it is not always exact to the decimal in this case).

Summary
Long story short, I do not recommend to use very off the scale variables, especially if mixed together. The way computers operate is not very favourable in these cases.
Moreover, intuitively it makes more sense to me to read there are ~10 ICU beds per 100,000 as opposed to comparing 0.000083 beds per capita in Russia vs 0.0003870 in Germany.


---

