Number: Difference between revisions

From Bohemia Interactive Community
Jump to navigation Jump to search
m (Fix link. Fix typos.)
m (Text replacement - "\{\{ *Wikipedia *\| *([-a-zA-Z0-9_#':%\/\\]+) *\| *([-a-zA-Z0-9_#':%\/\\ ]+) *\}\}" to "{{Link|https://en.wikipedia.org/wiki/$1|$2}}")
(18 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{SideTOC}}
{{TOC|side}}
A number is, depending on scope, either a [http://en.wikipedia.org/wiki/Single-precision_floating-point_format single precision floating-point number] (when talking about scripting) or a range of numerical types when talking about config context.
A number is, depending on scope, either a {{Link|https://en.wikipedia.org/wiki/Single-precision_floating-point_format|single precision floating-point number}} (when talking about scripting) or a range of numerical types when talking about config context.


==Scripting==
In SQF, there are multiple accepted number formats.
However, all of them will result in the same  {{Inline code|SCALAR}} ([[typeName]]) value type.


The '''<span style="color: #008000;">largest positive</span>''' number that can be archived is {{Inline code|3.4028235e38}} and the '''<span style="color: #800000;">largest negative</span>''' is {{Inline code|-3.4028235e38}}.<br>
== Scripting ==
It also is possible to generate positive or negative infinite values using either {{Inline code|1e39}} (string representation: {{Inline code|1.#INF}}) or {{Inline code|-1e39}} (string representation: {{Inline code|-1.#INF}}).


To check, if a number is finite, one can use the [[finite]] operator.
In [[SQF Syntax|SQF]], there are multiple accepted number formats.
However, all of them will result in the same {{hl|SCALAR}} ([[typeName]]) value type.


{{Informative|Regex to match all numbers in [[SQF_syntax|SQF]] is {{Inline code|<nowiki>(((\$|0x)[0-9a-fA-F]+)|(\.[0-9]+))|(\b[0-9]+(\.[0-9]+|[eE][-+]?[0-9]+)?)\b</nowiki>}}}}
The '''{{Color|#008000|largest positive}}''' number that can be achieved is {{hl|3.4028235e38}} and the '''{{Color|#800000|largest negative}}''' is {{hl|-3.4028235e38}}.<br>
{{Important|Due to technical limitations, the precision of floating-point numbers is limited. Please refer to [https://en.wikipedia.org/wiki/IEEE_754 IEEE 754] for more info about the technical details.}}
It also is possible to generate positive or negative infinity values using either {{hl|1e39}} (string representation: {{hl|1.#INF}}) or {{hl|-1e39}} (string representation: {{hl|-1.#INF}}).


===Decimal (Base 10)===
To check if a number is finite one can use the [[finite]] operator.
A decimal number is your normal {{Inline code|0.5}} syntax stuff with one extra: You may omit the initial pack of digits.
 
{{Feature|informative|Regex to match all numbers in [[SQF Syntax|SQF]] is {{hl|<nowiki>(((\$|0x)[0-9a-fA-F]+)|(\.[0-9]+))|(\b[0-9]+(\.[0-9]+|[eE][-+]?[0-9]+)?)\b</nowiki>}}}}
{{Feature|important|Due to technical limitations, the precision of floating-point numbers is limited. Please refer to {{Link|https://en.wikipedia.org/wiki/IEEE_754|IEEE 754}} for more info about the technical details.}}
 
=== Decimal (Base 10) ===
 
A decimal number is your normal {{hl|0.5}} syntax stuff with one extra: You may omit the initial pack of digits.


Some Examples would be:
Some Examples would be:
* {{Inline code|5.197}}
* {{hl|5.197}}
* {{Inline code| 0.47}}
* {{hl| 0.47}}
* {{Inline code| 16.0}}
* {{hl| 16.0}}
* {{Inline code|.8314}}
* {{hl|.8314}}
* {{Inline code|12345}}
* {{hl|12345}}
 
A regex catching these kind of numbers could look like this {{hl|<nowiki>((\.[0-9]+)|(\b[0-9]+(\.[0-9]+)?))\b</nowiki>}}
 
==== Scientific Notation ====
The {{Link|https://en.wikipedia.org/wiki/Scientific_notation|Scientific Notation}} is a way of expressing numbers that are too big or too small to be conveniently written in decimal form.
 
It starts of like a normal decimal and then gets expressed by an {{hl|E}} (Not case-sensitive, thus {{hl|e}} is also valid) followed by an '''optional''' {{hl|+}} or {{hl|-}} sign and ends with a range of digits.


A regex catching these kind of numbers could look like this {{Inline code|<nowiki>((\.[0-9]+)|(\b[0-9]+(\.[0-9]+)?))\b</nowiki>}}
Some examples would be:
* {{hl|1.23E4 ⇔ 1.23 ⋅ 10<sup>4 </sup> ⇔ 12300}}
* {{hl|5e-2  ⇔    5 ⋅ 10<sup>-2</sup> ⇔  0.05}}


====Scientific Notation====
A regex catching these kind of numbers could look like this  {{hl|([0-9]+.)?[0-9]+[eE][+-]?[0-9]+}}
The [https://en.wikipedia.org/wiki/Scientific_notation Scientific Notation] is a way of expressing numbers that are too big or too small to be conveniently written in decimal form.


It starts of like a normal decimal and then gets expressed by an {{Inline code|E}} (Not case-sensitive, thus {{Inline code|e}} is also valid) followed by an __optional__ {{Inline code|+}} or {{Inline code|-}} sign and ends with a range of digits.
=== Hexadecimal (Base 16) ===
 
In [[SQF Syntax|SQF]], {{Link|https://en.wikipedia.org/wiki/Hexadecimal|hexadecimal}} (also base 16, or hex) is a positional numeral system with a base of 16.
They start either with {{hl|0x}} or with a single {{hl|$}}.
 
This gets followed by one of the following characters: {{hl|0 1 2 3 4 5 6 7 8 9 A B C D E F}}.<br>
Note that casing does not matter, thus both {{hl|0xa}} and {{hl|0xA}} are valid.


Some Examples would be:
Some Examples would be:
* {{Inline code|1.23E4 ⇔ 1.23 ⋅ 10<sup>4 </sup> ⇔ 12300}}
* {{hl|0xa5}}
* {{Inline code|5e-2  ⇔    5 ⋅ 10<sup>-2</sup> ⇔  0.05}}
* {{hl|$5C}}
* {{hl|$FFFFFF}}
* {{hl|0x123ABC}}


A regex catching these kind of numbers could look like this {{Inline code|([0-9]+.)?[0-9]+[eE][+-]?[0-9]+}}
A regex catching these kind of numbers could look like this {{hl|<nowiki>((\$|0x)[0-9a-fA-F]+)\b</nowiki>}}


===Hexadecimal (Base 16)===
In [[SQF_syntax|SQF]], [https://en.wikipedia.org/wiki/Hexadecimal hexadecimal] (also base 16, or hex) is a positional numeral system with a base of 16.
They start either with {{Inline code|0x}} or with a single {{Inline code|$}}.


This gets followed by one of the following characters: {{Inline code|0 1 2 3 4 5 6 7 8 9 A B C D E F}}.<br>
== Config ==
Note that casing does not matter, thus both {{Inline code|0xa}} and {{Inline code|0xA}} are valid.


Some Examples would be:
Unlike scripting, configs actually do allow for multiple number types (Integer, [[Float]], etc). They are properly stored with their corresponding type in mind.
* {{Inline code|0xa5}}
{{Feature | Informative | In a config, a [[Number]] can also mean a [[Boolean]]: in [[Description.ext]] for example, <syntaxhighlight lang="cpp" inline>disabledAI = 1;</syntaxhighlight> means [[true]].}}
* {{Inline code|$5C}}
 
* {{Inline code|$FFFFFF}}
<syntaxhighlight lang="cpp">
* {{Inline code|0x123ABC}}
class MyClass
{
myInt = 1; // integer
myFloat = 0.01; // float
};


A regex catching these kind of numbers could look like this {{Inline code|<nowiki>((\$|0x)[0-9a-fA-F]+)\b</nowiki>}}
// description.ext example
disabledAI = 1; // boolean: 0 = false, everything else = true (usually 1)
</syntaxhighlight>


==Config==
{{Stub}}
Unlike scripting, configs actually do allow for multiple number types (integer, float, etc.).
They are stored proper with their corresponding type in mind.


<!--
== Floating-point Precision ==
The following used to be written down in here.
It was removed as it is not providing any informations whatsoever (Degrees, Radians), Redundant info or stuff that is not related to the numerical numbertype (parseNumber stuff).
In case anybody wants to add informations (for example: what a "poetic label" actually means and looks), it may be readded.
-->
<!--
==Degrees==


Degrees are a poetic label used to indicate a number returned from functions like [[acos]] and [[asin]]
Humans are typically used to performing mathematical calculations on the set of ''real numbers'' (ℝ), and there are no gaps between real numbers; there is always another real number between two real numbers. However, as mentioned above, every number in scripting is a ''floating-point number''. Because any given floating-point number can only consist of a finite amount of bits (a computer's memory is finite after all), any given floating-point format can only represent a finite amount of distinct numbers. Consequently, there are gaps between floating-point numbers.


It's special properties are that it will always supply a value from 0 to 360
This induces the following problem: There are real numbers that the computer does not have a binary representation for (and that it therefore can not work with) because there is no representation for these numbers in the specific floating-point format used by the computer. Of course, by extension, this also applies to the [[Real Virtuality]] Engine - there are real numbers that it does not have a representation for.


==Radians==
This issue is dealt with by rounding to the nearest number that can actually be represented as a floating-point number.
{| class="wikitable" style="margin: auto"
|-
! <var>n</var> ∈ ℝ !! <var>n</var> in {{arma3}}<br>(value of <sqf inline>n toFixed 20</sqf>)
|- style="background-color: lightgreen"
| 0 || 0.00000000000000000000
|- style="background-color: lightgreen"
| 1 || 1.00000000000000000000
|-
| 1.1 || 1.10000002384185790000
|- style="background-color: lightgreen"
| 2.5 || 2.50000000000000000000
|-
| 2.51 || 2.50999999046325680000
|}
Unfortunately, this rounding introduces a new problem in the form of unexpected, seemingly erroneous behaviour: For instance, despite being entirely correct mathematically, the expression <sqf inline>0.3 + 0.4 == 0.7</sqf> surprisingly returns [[false]] in {{arma3}}. In order to understand why this happens, examine the evaluation of the expression step by step:
# The 0.3 from the source code has to be rounded to 0.30000001192092896
# The 0.4 from the source code has to be rounded to 0.40000000596046448
# Now the addition can be performed: 0.30000001192092896 + 0.40000000596046448 = 0.70000004768371582 (that is the result with floating-point arithmetic; the result of the same addition in ℝ is 0.70000001788139344)
# The 0.7 from the source code has to be rounded to 0.69999998807907104
# Finally, the comparison <sqf inline>0.70000004768371582 == 0.69999998807907104</sqf> returns [[false]]


Another poetic label for a Number. Used in angular math computations with commands like [[rad]] and [[deg]]
To add to the confusion, <sqf inline>0.3 + 0.4</sqf> will actually output {{hl|0.7}} in the [[Arma 3: Debug Console|Debug Console]] or when used with commands like [[hint]] or [[systemChat]] - that is because numbers are rounded yet again when they are converted to [[String]] for the output. If this needs to be avoided, the [[toFixed]] command can be used to obtain the accurate value of a number.


==Scripting vs Addons==
Floating-point formats are designed so that their accuracy is highest for values close to the zero. As such, the gaps between floating-point numbers with small absolute values are also small, while the gaps between floating-point numbers with large absolute values become increasingly larger. For instance, any real number between 87,654,316 and 87,654,324 has to be rounded to 87,654,320 in {{arma3}}.
===Integers and Floats===
Note that unlike config.cpp's (addons), a ''Number'' in scripting language is '''ANY''' numeric entity. Floats, or integers. It is NOT the same as a config's [[Integer]] or [[Float]]. Number covers both types.


===Booleans===
=== Consequences ===


Note also, unlike config.cpp's, [[Boolean]] is a real type in scripting language. In addons, it is a poetic licence for a zero/non zero [[Integer]]. In Arma 3 command [[parseNumber]] has been extended to accept booleans:
* Fractional numbers should not be compared for equality. Instead of <sqf inline>0.3 + 0.4 == 0.7</sqf> one should use something like <sqf inline>_res = 0.3 + 0.4; _res > 0.7 - 0.000001 && _res < 0.7 + 0.000001</sqf>. Note that this is only necessary if fractional numbers are involved; if only whole numbers are involved, this procedure is not necessary.
* Large numbers can not always be incremented / decremented. For example, <sqf inline>87654320 + 1</sqf> returns 87,654,320 in Arma 3 (the next larger floating-point number after {{hl|87,654,320}} is {{hl|87,654,328}}).


<code>[[hint]] [[str]] [[parseNumber]] [[true]]; //1</code>
-->


[[Category: Data Types]]
[[Category: Data Types]]

Revision as of 01:47, 24 February 2023

A number is, depending on scope, either a single precision floating-point number (when talking about scripting) or a range of numerical types when talking about config context.


Scripting

In SQF, there are multiple accepted number formats. However, all of them will result in the same SCALAR (typeName) value type.

The largest positive number that can be achieved is 3.4028235e38 and the largest negative is -3.4028235e38.
It also is possible to generate positive or negative infinity values using either 1e39 (string representation: 1.#INF) or -1e39 (string representation: -1.#INF).

To check if a number is finite one can use the finite operator.

Regex to match all numbers in SQF is (((\$|0x)[0-9a-fA-F]+)|(\.[0-9]+))|(\b[0-9]+(\.[0-9]+|[eE][-+]?[0-9]+)?)\b
Due to technical limitations, the precision of floating-point numbers is limited. Please refer to IEEE 754 for more info about the technical details.

Decimal (Base 10)

A decimal number is your normal 0.5 syntax stuff with one extra: You may omit the initial pack of digits.

Some Examples would be:

  • 5.197
  • 0.47
  • 16.0
  • .8314
  • 12345

A regex catching these kind of numbers could look like this ((\.[0-9]+)|(\b[0-9]+(\.[0-9]+)?))\b

Scientific Notation

The Scientific Notation is a way of expressing numbers that are too big or too small to be conveniently written in decimal form.

It starts of like a normal decimal and then gets expressed by an E (Not case-sensitive, thus e is also valid) followed by an optional + or - sign and ends with a range of digits.

Some examples would be:

  • 1.23E4 ⇔ 1.23 ⋅ 104 ⇔ 12300
  • 5e-2 ⇔ 5 ⋅ 10-2 ⇔ 0.05

A regex catching these kind of numbers could look like this ([0-9]+.)?[0-9]+[eE][+-]?[0-9]+

Hexadecimal (Base 16)

In SQF, hexadecimal (also base 16, or hex) is a positional numeral system with a base of 16. They start either with 0x or with a single $.

This gets followed by one of the following characters: 0 1 2 3 4 5 6 7 8 9 A B C D E F.
Note that casing does not matter, thus both 0xa and 0xA are valid.

Some Examples would be:

  • 0xa5
  • $5C
  • $FFFFFF
  • 0x123ABC

A regex catching these kind of numbers could look like this ((\$|0x)[0-9a-fA-F]+)\b


Config

Unlike scripting, configs actually do allow for multiple number types (Integer, Float, etc). They are properly stored with their corresponding type in mind.

In a config, a Number can also mean a Boolean: in Description.ext for example, disabledAI = 1; means true.
class MyClass
{
	myInt = 1;		// integer
	myFloat = 0.01;	// float
};

// description.ext example
disabledAI = 1;		// boolean: 0 = false, everything else = true (usually 1)


Floating-point Precision

Humans are typically used to performing mathematical calculations on the set of real numbers (ℝ), and there are no gaps between real numbers; there is always another real number between two real numbers. However, as mentioned above, every number in scripting is a floating-point number. Because any given floating-point number can only consist of a finite amount of bits (a computer's memory is finite after all), any given floating-point format can only represent a finite amount of distinct numbers. Consequently, there are gaps between floating-point numbers.

This induces the following problem: There are real numbers that the computer does not have a binary representation for (and that it therefore can not work with) because there is no representation for these numbers in the specific floating-point format used by the computer. Of course, by extension, this also applies to the Real Virtuality Engine - there are real numbers that it does not have a representation for.

This issue is dealt with by rounding to the nearest number that can actually be represented as a floating-point number.

n ∈ ℝ n in Arma 3
(value of n toFixed 20)
0 0.00000000000000000000
1 1.00000000000000000000
1.1 1.10000002384185790000
2.5 2.50000000000000000000
2.51 2.50999999046325680000

Unfortunately, this rounding introduces a new problem in the form of unexpected, seemingly erroneous behaviour: For instance, despite being entirely correct mathematically, the expression 0.3 + 0.4 == 0.7 surprisingly returns false in Arma 3. In order to understand why this happens, examine the evaluation of the expression step by step:

  1. The 0.3 from the source code has to be rounded to 0.30000001192092896
  2. The 0.4 from the source code has to be rounded to 0.40000000596046448
  3. Now the addition can be performed: 0.30000001192092896 + 0.40000000596046448 = 0.70000004768371582 (that is the result with floating-point arithmetic; the result of the same addition in ℝ is 0.70000001788139344)
  4. The 0.7 from the source code has to be rounded to 0.69999998807907104
  5. Finally, the comparison 0.70000004768371582 == 0.69999998807907104 returns false

To add to the confusion, 0.3 + 0.4 will actually output 0.7 in the Debug Console or when used with commands like hint or systemChat - that is because numbers are rounded yet again when they are converted to String for the output. If this needs to be avoided, the toFixed command can be used to obtain the accurate value of a number.

Floating-point formats are designed so that their accuracy is highest for values close to the zero. As such, the gaps between floating-point numbers with small absolute values are also small, while the gaps between floating-point numbers with large absolute values become increasingly larger. For instance, any real number between 87,654,316 and 87,654,324 has to be rounded to 87,654,320 in Arma 3.

Consequences

  • Fractional numbers should not be compared for equality. Instead of 0.3 + 0.4 == 0.7 one should use something like _res = 0.3 + 0.4; _res > 0.7 - 0.000001 && _res < 0.7 + 0.000001. Note that this is only necessary if fractional numbers are involved; if only whole numbers are involved, this procedure is not necessary.
  • Large numbers can not always be incremented / decremented. For example, 87654320 + 1 returns 87,654,320 in Arma 3 (the next larger floating-point number after 87,654,320 is 87,654,328).