Skip to content
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

Numbers #62

Merged
merged 4 commits into from
Oct 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions 1-js/05-data-types/02-number/1-sum-interface/solution.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@


```js run demo
let a = +prompt("The first number?", "");
let b = +prompt("The second number?", "");

alert( a + b );
```

Note the unary plus `+` before `prompt`. It immediately converts the value to a number.
注意在 `prompt` 之前的一元正號 `+`,它將值立刻轉換為數值。

否則,`a` 和 `b` 是個字串,所以它們的加總將會是字串連接,也就是:`"1" + "2" = "12"`。

Otherwise, `a` and `b` would be string their sum would be their concatenation, that is: `"1" + "2" = "12"`.
7 changes: 4 additions & 3 deletions 1-js/05-data-types/02-number/1-sum-interface/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ importance: 5

---

# Sum numbers from the visitor
# 加總由訪問者輸入的數值

Create a script that prompts the visitor to enter two numbers and then shows their sum.
建立一個腳本,提示(prompt)訪問者輸入兩個數值,然後顯示它們的總和。

[demo]

P.S. There is a gotcha with types.
註:類型會有個問題。

17 changes: 8 additions & 9 deletions 1-js/05-data-types/02-number/2-why-rounded-down/solution.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
Internally the decimal fraction `6.35` is an endless binary. As always in such cases, it is stored with a precision loss.
在十進位分數 `6.35` 的內部是個無窮二進位,在這種情況下,它的存放會有著精度損失。

Let's see:
來看這:

```js run
alert( 6.35.toFixed(20) ); // 6.34999999999999964473
```

The precision loss can cause both increase and decrease of a number. In this particular case the number becomes a tiny bit less, that's why it rounded down.
精度損失可能會導致數值的增減,在這個特殊情況下,數值變得稍微小了點,這就是為什麼它被向下進位了。

And what's for `1.35`?
`1.35` 呢?

```js run
alert( 1.35.toFixed(20) ); // 1.35000000000000008882
```

Here the precision loss made the number a little bit greater, so it rounded up.
精度損失讓該數值稍微大了些,所以它被向上進位。

**How can we fix the problem with `6.35` if we want it to be rounded the right way?**
**若我們想要它正確的進位,該如何修正 `6.35` 的這個問題?**

We should bring it closer to an integer prior to rounding:
我們應該在進位前讓它更靠近整數:

```js run
alert( (6.35 * 10).toFixed(20) ); // 63.50000000000000000000
```

Note that `63.5` has no precision loss at all. That's because the decimal part `0.5` is actually `1/2`. Fractions divided by powers of `2` are exactly represented in the binary system, now we can round it:

注意這個 `63.5` 完全沒有精度損失,這是因為小數部分的 `0.5` 事實上為 `1/2`。被 `2` 的次方所除的除法可以在二進位系統中被完全表示出來,現在我們可以進位它了:

```js run
alert( Math.round(6.35 * 10) / 10); // 6.35 -> 63.5 -> 64(rounded) -> 6.4
Expand Down
10 changes: 5 additions & 5 deletions 1-js/05-data-types/02-number/2-why-rounded-down/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ importance: 4

---

# Why 6.35.toFixed(1) == 6.3?
# 為什麼 6.35.toFixed(1) == 6.3

According to the documentation `Math.round` and `toFixed` both round to the nearest number: `0..4` lead down while `5..9` lead up.
根據文件 `Math.round` `toFixed` 兩者皆進位到最近的數值:`0..4` 向下捨去,而 `5..9` 向上提升。

For instance:
舉個例:

```js run
alert( 1.35.toFixed(1) ); // 1.4
```

In the similar example below, why is `6.35` rounded to `6.3`, not `6.4`?
跟上面類似的例子中,為什麼 `6.35` 會進位為 `6.3` 而非 `6.4`

```js run
alert( 6.35.toFixed(1) ); // 6.3
```

How to round `6.35` the right way?
要如何正確地進位到 `6.35` 呢?

Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ function readNumber() {
alert(`Read: ${readNumber()}`);
```

The solution is a little bit more intricate that it could be because we need to handle `null`/empty lines.
解法較為複雜些,因為我們需要處理 `null`/空行。

So we actually accept the input until it is a "regular number". Both `null` (cancel) and empty line also fit that condition, because in numeric form they are `0`.
因此我們實際上一直接收輸入的東西,直到它是個 "正常的數值" 為止。`null`(取消)和空行這兩者也都符合此條件,因為在數值格式中它們都是 `0`

After we stopped, we need to treat `null` and empty line specially (return `null`), because converting them to a number would return `0`.
在我們停下來之後,需要是對 `null` 和空行特別對待(return `null`),因為轉換它們為數值將會回傳 `0`

8 changes: 4 additions & 4 deletions 1-js/05-data-types/02-number/3-repeat-until-number/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ importance: 5

---

# Repeat until the input is a number
# 重複動作直到輸入的是個數值為止

Create a function `readNumber` which prompts for a number until the visitor enters a valid numeric value.
建立一個函式 `readNumber` 以提示(prompt)輸入數值,直到訪問者真的輸入有效數值為止。

The resulting value must be returned as a number.
結果值必須以數值回傳。

The visitor can also stop the process by entering an empty line or pressing "CANCEL". In that case, the function should return `null`.
訪問者也可以透過輸入空行或按下 "CANCEL" 來停止程序。在這個情況下,函式應該要回傳 `null`

[demo]

11 changes: 6 additions & 5 deletions 1-js/05-data-types/02-number/4-endless-loop-error/solution.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
That's because `i` would never equal `10`.
這是因為 `i` 永遠不會等於 `10`

Run it to see the *real* values of `i`:
執行這段來看看 `i` *真實* 的值:

```js run
let i = 0;
Expand All @@ -10,8 +10,9 @@ while (i < 11) {
}
```

None of them is exactly `10`.
它們之中沒有恰好為 `10` 的值。

Such things happen because of the precision losses when adding fractions like `0.2`.
這種事情發生於因為加上像是`0.2` 這樣的分數,而導致的精度損失。

結論:在使用十進位小數時,避免相等性確認。

Conclusion: evade equality checks when working with decimal fractions.
4 changes: 2 additions & 2 deletions 1-js/05-data-types/02-number/4-endless-loop-error/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ importance: 4

---

# An occasional infinite loop
# 偶發的無窮迴圈

This loop is infinite. It never ends. Why?
這個迴圈是無窮的,它永不停止。為什麼?

```js
let i = 0;
Expand Down
10 changes: 5 additions & 5 deletions 1-js/05-data-types/02-number/8-random-min-max/solution.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
We need to "map" all values from the interval 0..1 into values from `min` to `max`.
我們需要 "對應" 0..1 區間內的所有值至 `min` `max` 之間的值上。

That can be done in two stages:
可在兩步驟內完成:

1. If we multiply a random number from 0..1 by `max-min`, then the interval of possible values increases `0..1` to `0..max-min`.
2. Now if we add `min`, the possible interval becomes from `min` to `max`.
1. 若我們對 `max-min` 乘上一個在 0..1 之間的隨機數,則可能值的區間會由 `0..1` 增加至 `0..max-min`
2. 現在若我們加上 `min`,則區間將變成 `min` `max`

The function:
該函式:

```js run
function random(min, max) {
Expand Down
9 changes: 5 additions & 4 deletions 1-js/05-data-types/02-number/8-random-min-max/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ importance: 2

---

# A random number from min to max
# min max 的隨機數

The built-in function `Math.random()` creates a random value from `0` to `1` (not including `1`).
內建函式 `Math.random()` 建立一個從 `0` `1` 的隨機值(不包括 `1`)。

Write the function `random(min, max)` to generate a random floating-point number from `min` to `max` (not including `max`).
寫個函式 `random(min, max)` `min` `max` 中產生隨機的浮點數(不包括 `max`)。

Examples of its work:
可行的範例:

```js
alert( random(1, 5) ); // 1.2345623452
alert( random(1, 5) ); // 3.7894332423
alert( random(1, 5) ); // 4.3435234525
```

27 changes: 14 additions & 13 deletions 1-js/05-data-types/02-number/9-random-int-min-max/solution.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# The simple but wrong solution
# 簡單但錯誤的解法

The simplest, but wrong solution would be to generate a value from `min` to `max` and round it:
最簡單卻錯誤的解法,是產生由 `min` `max` 的值,再進位它:

```js run
function randomInteger(min, max) {
Expand All @@ -11,28 +11,28 @@ function randomInteger(min, max) {
alert( randomInteger(1, 3) );
```

The function works, but it is incorrect. The probability to get edge values `min` and `max` is two times less than any other.
這個函式可以運行,但它不正確。得到邊緣值 `min` `max` 的機率比其它值還要少了兩倍。

If you run the example above many times, you would easily see that `2` appears the most often.
若你執行上述範例許多次,你將會很容易就看到 `2` 較常出現。

That happens because `Math.round()` gets random numbers from the interval `1..3` and rounds them as follows:
那是因為 `Math.round()` 由區間 `1..3` 之間得到隨機數,並像下面這樣進位:

```js no-beautify
values from 1 ... to 1.4999999999 become 1
values from 1.5 ... to 2.4999999999 become 2
values from 2.5 ... to 2.9999999999 become 3
```

Now we can clearly see that `1` gets twice less values than `2`. And the same with `3`.
現在我們可以清楚看到 `1` `2` 還少了兩倍,且同樣情況對 `3` 也是。

# The correct solution
# 正確的解法

There are many correct solutions to the task. One of them is to adjust interval borders. To ensure the same intervals, we can generate values from `0.5 to 3.5`, thus adding the required probabilities to the edges:
對此課題有許多正確的解法,其中一種是調整區間邊界。要保證同樣的區間,我們可以從 `0.5 3.5` 之間來生成值,故此可讓邊緣加上所需要的機率:

```js run
*!*
function randomInteger(min, max) {
// now rand is from (min-0.5) to (max+0.5)
// 現在 隨機值從(min-0.5)到(max+0.5
let rand = min - 0.5 + Math.random() * (max - min + 1);
return Math.round(rand);
}
Expand All @@ -41,12 +41,12 @@ function randomInteger(min, max) {
alert( randomInteger(1, 3) );
```

An alternative way could be to use `Math.floor` for a random number from `min` to `max+1`:
另一個替代的做法是對於 `min` `max+1` 之間的隨機數使用 `Math.floor`:

```js run
*!*
function randomInteger(min, max) {
// here rand is from min to (max+1)
// 這邊的隨機值由 min 到(max+1
let rand = min + Math.random() * (max + 1 - min);
return Math.floor(rand);
}
Expand All @@ -55,12 +55,13 @@ function randomInteger(min, max) {
alert( randomInteger(1, 3) );
```

Now all intervals are mapped this way:
現在所有區間以這樣的方式被對應:

```js no-beautify
values from 1 ... to 1.9999999999 become 1
values from 2 ... to 2.9999999999 become 2
values from 3 ... to 3.9999999999 become 3
```

All intervals have the same length, making the final distribution uniform.
所有區間有著同樣的長度,使得最後結果是均勻分佈的。

12 changes: 6 additions & 6 deletions 1-js/05-data-types/02-number/9-random-int-min-max/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ importance: 2

---

# A random integer from min to max
# min max 的隨機整數

Create a function `randomInteger(min, max)` that generates a random *integer* number from `min` to `max` including both `min` and `max` as possible values.
建立一個函式 `randomInteger(min, max)` 來生成一個從 `min` `max` 的隨機 *整數*,包含 `min` `max` 兩者皆為可能的值。

Any number from the interval `min..max` must appear with the same probability.
任何在 `min..max` 區間的數值必須以相同的機率出現。


Examples of its work:
可行的範例:

```js
alert( randomInteger(1, 5) ); // 1
alert( randomInteger(1, 5) ); // 3
alert( randomInteger(1, 5) ); // 5
```

You can use the solution of the [previous task](info:task/random-min-max) as the base.
你可以使用 [前一個課題](info:task/random-min-max) 的解答作為基礎來思考。

Loading