Number API Functions
This document lists most useful (and most often needed) functions. Be aware, that there are many more to be found in either the class references or via the builtin class browser.
Reference: Integer, Float, Fraction, ScaledDecimal, Complex which all inherit from Number
Inhaltsverzeichnis
- 1 Literals (i.e. Constant Numbers)
- 2 Wellknown Constant Numbers
- 3 Float Representations
- 4 Fractions
- 5 Scaled Decimals
- 6 Fixed Decimals
- 7 Complex Numbers
- 8 Measurement Values
- 9 Physical Values
- 10 Operations with Mixed Types
- 11 Most Common/Useful Operations
- 12 Examples
- 13 Printf Format Specifier
- 14 Scanf Format Specifier
Literals (i.e. Constant Numbers)[Bearbeiten]
Literals are constants as written in elementary Smalltalk code and also given as freeze value to a pin or initial value to a variable.
Integer Literals[Bearbeiten]
1234
or
16rFFAA0xaffe
or
2r01010b101010
or
8r3770o377
<N>rXXX
1234567890123456789012345678901234567890
-123456789012345678901234567890
- integer constant; decimal, hex, binary, octal or any base N;
integers may be arbitrary long
- integer constant; decimal, hex, binary, octal or any base N;
Floating Point Literals (Limited Precision Rationals)[Bearbeiten]
0.5
1e5
-1.2e-3
1345.6789q5
- float constant; actually double precision;
use "q" instead of "e" for extra precision (extended IEEE floats)
- float constant; actually double precision;
Fraction Literals[Bearbeiten]
(4/3)
(523423432/3)
- fraction constants (numerator / denominator); these are exact
Scaled Decimal Literals[Bearbeiten]
123.456s2
100s2
- scaled decimal; prints itself rounded to 2 fractional digits eg. "123.46" or "100.00" (although internally, the full precision is kept for further operations)
Complex Number Literals[Bearbeiten]
(4+3i)
(4.3+3.1i)
5.0 i
- a complex number (real part / imaginary part)
Wellknown Constant Numbers[Bearbeiten]
A few constants are known by name. They are answered by corresponding getter messages sent to the number class (of which you want the constant):
Float pi
- pi as IEEE double precision number
LongFloat pi
- pi as IEEE extended precision number
Float ln2
Float ln10
Float phi
Float sqrt2
Float e
Float Representations[Bearbeiten]
Standard Float Representations[Bearbeiten]
For traditional reasons, the name "Float" refers to IEEE double precision floating point numbers in expecco, whereas IEEE single precision floats are called "ShortFloats".
There is usually no need to explicitly use or refer to ShortFloats: modern CPUs usually process them as fast as doubles. However, you may need them to either simulate single precision arithmetic (which may show different convergence behavior in some series computations) or to exchange binary data with other systems (i.e. to generate a byteArray containing the float's bits).
Float[Bearbeiten]
Floats (double precision IEEE floats) are stored in 64 bits, having an 11-bit exponent and a 52+1 bit mantissa (1 bit is hidden due to normalization).
This gives roughly 15 digits of precision.
ShortFloat[Bearbeiten]
ShortFloats (single precision IEEE floats) are stored in 32 bits, having an 8-bit exponent and a 23+1 bit mantissa (1 bit is hidden due to normalization).
This gives roughly 7 digits of precision.
LongFloat[Bearbeiten]
LongFloats (extended precision IEEE floats) are stored in 80 bits, having an 15-bit exponent and a 64 bit mantissa.
This gives roughly 19 digits of precision.
Floats print themself with either a decimal point or an exponent indicator 'e', eg. "0.5", "10.0" or "1.3e3"
Experimental Extra Float Representations[Bearbeiten]
Expecco includes experimental versions for higher precision floats. Please do not use them for production code. They are considered being "work in progress", and may or may not work as expected. Especially trigonometric and other math functions are known to be erroneous.
QDouble[Bearbeiten]
QDoubles use 4 double precision floats (holding the unevaluated sum of 4 doubles) to represent a float with roughly 200 bits of precision (actually often more, depending on the values).
QDoubles are able to represent sums/differences of a very large float with a very small float.
For example (1e200 + 1e-15) - 1e200 -> 0.0
(floats loose the small value), whereas in (1e200 asQDouble + 1e-15) - 1e200 -> 1e-15
it is preserved.
- QDoubles are thus able to represent sums of wildly distant numbers.
- With regular floats, the following computations all deliver a wrong result:
1e200 + 1e-15 + 1e-100 -> 1E+200 (loosing 1e-15 + 1e-100) (1e200 + 1e-15 + 1e-100) - 1e200 -> 0 (wrong; lost 1e-15 + 1e-100) (1e200 + 1e-15 + 1e-100) - 1e200 - 1e-15 -> -1e-15 (wrong) (1e200 + 1e-15 + 1e-100) - 1e200 - 1e-100 -> -1E-100 (wrong) (1e200 + 1e-15 + 1e-100) - 1e200 - 1e-15 - 1e-100 -> -1E-015 (wrong)
whereas with QDoubles, we get:
1e200 asQDouble + 1e-15 + 1e-100 -> 1E+200 (printed, actual value is correct) (1e200 asQDouble + 1e-15 + 1e-100) - 1e200 -> 1.0e-15 (correct) (1e200 asQDouble + 1e-15 + 1e-100) - 1e200 - 1e-15 -> 1E-100 (correct) (1e200 asQDouble + 1e-15 + 1e-100) - 1e200 - 1e-100 -> 1E-015 (correct) (1e200 asQDouble + 1e-15 + 1e-100) - 1e200 - 1e-15 - 1e-100 -> 0.0 (correct)
or another example:
t := 1234 + 0.567890 + 0.00000012345 + 0.000000000006789. a := t - 1234. "/ 0.567890123456891 (mhmh ?) b := a - 0.567890. "/ 1.23456891154561E-07 (mhmh ?) c := b - 0.00000012345. "/ 6.89115456081139E-12 (mhmh ?) d := c - 0.000000000006789. "/ 1.0215456081139E-13 (wrong)
whereas:
t := 1234 asQDouble + 0.567890 + 0.00000012345 + 0.000000000006789. a := t - 1234. "/ 0.56789012346 (mhmh ?) b := a - 0.567890. "/ 1.23456789e-7 (mhmh ?) c := b - 0.00000012345. "/ 6.789E-12 (correct) d := c - 0.000000000006789. "/ 0.0 (correct)
- Due to the extra processing overhead, operations are slower than with doubles or extended doubles.
QuadFloat[Bearbeiten]
QuadFloats use the 128 bit IEEE quadruple precision binary128 format, with 15 exponent bits, providing roughly 34 digits of precision.
QuadFloats are software emulated, and thus slower than both regular floats and also slower than QDoubles.
OctaFloat[Bearbeiten]
OctaFloats use the 256 bit IEEE octuple binary256 format, with 19 exponent bits, providing roughly 70 digits of precision.
OctaFloats are also software emulated, and slower than QuadFloats.
LargeFloat[Bearbeiten]
LargeFloats use an arbitrary (configurable) number of bits to represent floats with any precision.
They are completely software emulated which makes operations much slower than with other floats.
Fractions[Bearbeiten]
Fractions are returned from integer divisions; i.e. when both "a" and "b" are integers and "a / b" does not result in an integral result.
Fractions are exact; no precision is lost. Results of arithmetic operations are reduced and possibly yield integers. Thus:
(1/3) * (1/3) => (1/9)
and:
(1/3) * 9 => 3 (an exact integer)
Fractions print themself as "(a / b)".
Scaled Decimals[Bearbeiten]
These print themself rounded to a specified number of fractional digits (the so called scale).
For example, "1234.567 asScaledDecimal:2
" will print itself as "1234.57" (i.e. rounded).
However, internally the full precision is kept so an arithmetic operation will still deliver a correct result.
Scaled decimals are perfect to present values to a user or in a report in a "human friendly" rounded format.
Example:
a := 1234.567 asScaledDecimal:2. a print. => '1234.57' b := 23.007 asScaledDecimal:2 b print. => '23.01' (a + b) print. => '1257.57'
This is because the sum (a+b) is actually (1234.567 + 23.007 = 1257.574), which is printed as '1257.57' (rounded).
However, this will look strange (i.e. wrong) if monetary values are presented this way, eg. on an invoice's summation. Here, we expect a sum of amounts to be the sum of previously listed values (think of sales tax being computed, giving a rounded Cent-value). See FixedDecimal below for a better solution.
ScaledDecimals can be rounded to their scale, so that further computation are taking that value. Thus taking the above values rounded:
a := a roundedToScale. b := b roundedToScale. (a + b) print. => '1257.58'
shows the correct value in a table.
You can also use "truncatedToScale
", to continue arithmetic with the truncated value.
Fixed Decimals[Bearbeiten]
(new with expecco 21.2)
Similar to ScaledDecimals; however, these do NOT hold the correct result, but instead always round to the specified scale and thus the value used for further operations is the (rounded) value printed.
Arithmetic operations will deliver a rounded result. Fixed decimals are good to represent money, especially when computing and printing sums of monetary values eg. in an invoice.
Example:
a := 1234.567 asFixedDecimal:2. a print. => '1234.57' b := 23.007 asFixedDecimal:2 b print. => '23.01' (a + b) print. => '1257.58'
This looks correct eg. in an invoice's sum.
Be aware that converting a float to a FixedDecimal and back will not necessarily return the starting number, unlike ScaledDecimals. FixedDecimals do NOT preserve the original value.
If you have a pre 21.2 version, the FixedDecimal behavior can be "simulated" by forcing the decimal to round the internal value to the shown scale (as described above).
Complex Numbers[Bearbeiten]
Are created as constants "(a + b i)" or created with "Complex real:a imaginary:b".
An imaginary is created with the "i" message (eg. "5 i" yields (0 + 5 i).
Complex numbers print themself as "(a + b i)".
Complex results can also be returned from eg. square root (sort) and logarithm (log, ln) operations IFF imaginary results are trapped. I.e.
-4 sqrt
will report an error, whereas:
Number trapImaginary:[ -4 sqrt ]
will return a complex result.
Measurement Values[Bearbeiten]
These hold an error percentage in addition to the actual value. These are useful to track upper and lower bounds of a measured or estimated value. Arithmetic operations will keep this error in the result.
They can be constructed from any number via the "±" or "±%" binary operators:
(
aNumber±
errRange)
- a measurement value with ± an absolute error of errRange.
(
aNumber±%
percentage)
- a measurement value with a relative error of percentage.
For example, "(50 ± 3)" represents a measurement value with 6% accuracy (i.e. the actual value is somewhere in the interval [50-3 .. 50+3]); and "(100 ±% 3)" represents a measurement value with 3% accuracy (i.e. the value is in [100-3 .. 100+3]).
Measurement values are not real numbers, but can in most parts treated like one (i.e. the usual arithmetic operations are supported).
Physical Values[Bearbeiten]
These hold a number or measurement value in addition to a unit (eg. meter, kilogram, volt, ampere, etc.). They are documented in depth in a separate part of this wiki. Physical values are created via unit operators.
For example, "50 volt" represents a voltage value of 50 volts.
Physical values values are not numbers, but can in most parts be treated like one (i.e. most arithmetic operations are supported).
100 volt * 3
yields "300 V". And:
100 volt * 0.1 ampere
yields "10 W" (watt).
Physical values can also be combined with measurement values:
100 volt ±% 3
represents a measured voltage with 3% possible error (i.e. "(100 ± 3) V"). And:
10 volt ± 2 volt
represents a measured voltage with 20% error (i.e. value in [8 .. 12] V")
Operations with Mixed Types[Bearbeiten]
Normally, there is no need for explicit conversion between number types. The result of mixed operations is the computed with the type of the operand which has the higher "generality". The order of generalities is:
Integer < Fraction < ScaledDecimal < FixedDecimal < Float32 < Float64 < Float80 < Complex
Thus, when a calculation involves both an integer and a fraction, the result will be a fraction (unless the result can be reduced to an integer).
When an operation involves a float and an integer or fraction, the result will be a float.
When either one is a complex, the result will also be.
MeasurementValues[Bearbeiten]
Automatic conversion is also performed when MeasurementValues are involved:
aMeasurementValue +
aNumber => MeasurementValue
aMeasurementValue -
aNumber => MeasurementValue
- the result will have the same error as the receiver. Eg. "(10 ± 1) + 10" yields "(20 ± 1)".
aMeasurementValue *
aNumber => MeasurementValue
aMeasurementValue /
aNumber => MeasurementValue
- the error will also be scaled by aNumber. Eg. "(10 ± 1) * 10" yields "(100 ± 10)".
PhysicalValues[Bearbeiten]
PhysicalValues can only be scaled by a scalar value; addition and subtraction are not allowed:
aPhysicalValue +
aNumber => error
aPhysicalValue -
aNumber => error
- not allowed
aPhysicalValue *
aNumber => aPhysicalValue
aPhysicalValue /
aNumber => aPhysicalValue
- for example, "10 volt * 10" gives "100 volt".
Most Common/Useful Operations[Bearbeiten]
Testing[Bearbeiten]
aNumber isFinite
=> Boolean
- Check if number is not infinity and not NaN:
aNumber isInfinite
=> Boolean
- Check if number is either positive infinity (INF) or negative infinity (-INF):
aNumber isNaN
=> Boolean
- Check if number is NaN ("Not a Number"):
aNumber isInteger
=> Boolean
- Check if number is an integral number.
aNumber isFraction
=> Boolean
- Check if number is a fractional number.
aNumber isComplex
=> Boolean
- Check if number is a complex number.
aNumber negative
=> Boolean
- same as
aNumber < 0
- same as
aNumber positive
=> Boolean
- same as
aNumber >= 0
- same as
aNumber strictlyPositive
=> Boolean
- same as
aNumber > 0
- same as
anInteger isPrime
=> Boolean
- true if the number is a prime number
anInteger isPowerOf2
=> Boolean
- true if there exists an n, such that 2ˆn equals the number
anInteger isPowerOf:
b => Boolean
- true if there exists an n, such that bˆn equals the number
anInteger nextPrime
=> anInteger
anInteger nextPowerOf2
=> anInteger
Arithmetic[Bearbeiten]
aNumber +
aNumber => Number
aNumber -
aNumber => Number
aNumber *
aNumber => Number
aNumber /
aNumber => Number
- The usual arithmetic operators.
- All of the above allow operands of any number type, and will generate a result as appropriate. When dividing integers, an exact result is returned (either integer or fraction). If any of the arguments is inexact (i.e. a floating point number), the result will be inexact. If both are exact, the result will be exact. Fractional results are reduced to the greatest common divisor as denominator.
- Notice, that they are evaluated left to right, without special precedences.
- Thus you should always use parentheses to group expressions when there are two or more operators in an arithmetic expression.
- The usual arithmetic operators.
aNumber **
aNumber => Number
aNumber raisedTo:
aNumber => Number
- exponentiation (raising to a power)
- Examples:
2 ** 20 => 1048576 4 ** 3.5 => 128.0 100 ** 0.5 => 10.0
aNumber //
aNumber => Integer
aNumber \\
aNumber => Integer
- Truncated result and remainder (towards the next smaller integer i.e. towards negative infinity).
The following equation holds:(a // b) * b + (a \\ b) = a
- Examples:
- Truncated result and remainder (towards the next smaller integer i.e. towards negative infinity).
100 // 3 => 33 100 \\ 3 => 1
-100 // 3 => -34 -100 \\ 3 => 2
aNumber quo:
aNumber => Integer
aNumber rem:
aNumber => Integer
- Truncated result (towards zero) and corresponding remainder.
For positive arguments, this is the same as the above, for negative args, a different result is returned.
However, the equation is similar to above:(a quo: b) * b + (a rem: b) = a
- Examples:
- Truncated result (towards zero) and corresponding remainder.
100 quo: 3 => 33 100 rem: 3 => 1
-100 quo: 3 => -33 -100 rem: 3 => -1
Mathematical and Trigonometric Functions[Bearbeiten]
The usual operations are provided as unary messages to the number:
aNumber ln
=> Number
aNumber log10
=> Number
aNumber log2
=> Number
aNumber log:
base => Number
- logarithm (natural, base10, base2 or arbitrary base).
- These are not restricted to floats; they can also be applied to big integers,
as in:1000 factorial ln
- By default, an error is reported for negative numbers;
- to get a complex result, use "
Complex trapImaginary:[ aNumber ln ]
".
aNumber sqrt
=> Number
aNumber integerSqrt
=> Number
- square root and truncated square root
By default, an error is reported for negative numbers;
to get a complex result, use "Complex trapImaginary:[ aNumber sqrt ]
".
aNumber cbrt
=> Number
aNumber integerCbrt
=> Number
- cubic root and truncated cubic root.
aNumber exp
=> Number
number1 raisedTo:
number2 => Number
number1 **
number2 => Number
- exponentiation; the "**" binary operator is an alias for "raisedTo:".
aNumber sin
=> Number
aNumber cos
=> Number
aNumber tan
=> Number
aNumber cot
=> Number (cotangent)
aNumber sec
=> Number (secant)
aNumber csc
=> Number (cosecant)
aNumber arcSin
=> Number
aNumber arcCos
=> Number
aNumber arcTan
=> Number
aNumber arcTan2:
x => Number
- trigonometric functions
aNumber sinh
=> Number
aNumber cosh
=> Number
aNumber tanh
=> Number
aNumber arSinh
=> Number
aNumber arCosh
=> Number
aNumber arTanh
=> Number
- hyperbolic functions
Bitwise Operators[Bearbeiten]
integer1 bitAnd:
integer2 => Integer
integer1 bitOr:
integer2 => Integer
integer1 bitXor:
integer2 => Integer
integer1 bitShift:
count => Integer
- left shift if count is positive; right shift if negative
integer1 leftShift:
count => Integer
integer1 rightShift:
count => Integer
integer1 bitTest:
integer2 => Boolean
- integer2 is used as a mask (i.e. bitTest returns true if any bit in the mask is set in the left operand i.e. (i1 & i2) not equal 0
integer1 bitAt:
bitNr => integer (0 or 1)
- extract the nth bit, with bitNr starting at 1
integer highBit
=> integer (1..)
- the bit number of the highest bit, with bitNr starting at 1; zero if no bit is set
integer lowBit
=> integer (1..)
- the bit number of the lowest bit, with bitNr starting at 1; zero if no bit is set
Printing[Bearbeiten]
Numbers can print themself on an output stream, or convert themself to a string:
aNumber printOn:
aStream => void
aNumber printOn:
aStream radix:
base => void
aNumber printOn:
aStream leftPaddedTo:
length => void
aNumber printOn:
aStream leftPaddedTo:
length with:
padCharacter => void
aNumber printOn:
aStream paddedTo:
length => void
aNumber printOn:
aStream paddedTo:
length with:
padCharacter => void
aNumber printString
=> String
aNumber printStringRadix:
base => String
aNumber printStringLeftPaddedTo:
length => String
aNumber printStringLeftPaddedTo:
length with:
padCharacter => String
aNumber printStringPaddedTo:
length => String
aNumber printStringPaddedTo:
length with:
padCharacter => String
- The above generate a standard format, which should fit most needs. The padded variants fill with either space or the explicit padCharacter. The printOn: variants will send the string to an output stream; the printString variants will return the string.
formatString printf:
{ arg... } on:
aStream => void
formatString printf:
{ arg... } => String
- More fine control is available via the printf functions, which also offer a range of options to fill left or right, to control printing of the sign and to fill with zeros.
- These two interpret the receiver as a C-printf-style format string, and an argument vector as first argument (use a brace-array constructor or pass a collection as argument).
Thus, multiple values are printed as in the following example:
'%04x %3d %+4.3f\n' printf:{ 123 . 4 . 3.14159 } on:Transcript
- Individual conversions (to a string) can also be done with:
aNumber printfPrintString:
formatString => String
- Examples:
'% .4f' printf:{Float pi} => ' 3.1416' (space after % ensures space for sign) '% .4f' printf:{Float pi negated} => '-3.1416' (space after % ensures space for sign) '%+.4f' printf:{Float pi} => '+3.1416' ('+' after % enforces sign) '%+.4f' printf:{Float pi negated} => '-3.1416' ('+' after % enforces sign)
- Please refer to a C-printf manual page (eg. https://en.wikipedia.org/wiki/Printf_format_string).
- Notice that printf accepts C-style character escapes (which is not the case in general with Smalltalk string constants)
Reading from Streams / Converting from Strings[Bearbeiten]
Numbers can be read from a stream or converted from a string. There are slight differences between them:
- when reading from a stream of characters, the stream will be positioned after the number. So any non-digit character(s) after the number's characters will be returned by future read operations.
- when converting from a string, no extra characters are expected/allowed after the number's digits, except for whitespace. Thus you'll usually get an error when trying to convert a string with garbage characters after the number (which is not the case when reading from a stream).
Therefore, if you want to read a number from a string which may habe garbage characters after the digits, you should first create a read-stream on the string, and then read the number from the stream (i.e. "Number readFrom:(someString readStream). instead of "Number fromString:someString"
Numbers are read by sending the Number-class a "readFrom:" or a "fromString:" message. If the class is the abstract class Number, then the read code will itself figure out, what kind of number to return. If the given class is a concrete class (Float, Integer, Fraction etc.), you will get an instance of that class, unless the characters o not represent a valid number (of that class). In that case, an error is reported.
By default, errors are reported by raising an exception, unless you provide an error-handler as argument to the reader; more on that below.
Number readFrom:
aStream => someNumber or error
- this can return any of the number types
Number readFrom:
aStream onError:
[ errorValue ] => someNumber or errorValue
- errorValue (which is a Smalltalk block), can be a constant, an arbitrary Smalltalk expression or even show a warn dialog or do whatever you like
Number fomString:
aString => someNumber or error
Number fromString:
aString onError:
[ errorValue ] => someNumber or fallBackValue
Integer readFrom:
aStream
Integer readFrom:
aStream onError:[...]
Float readFrom:
aStream
Float readFrom:
aStream onError:[...]
Integer fromString:
aStream
Integer fromString:
aStream onError:[...]
Float fromString:
aStream
Float fromString:
aStream onError:[...]
- similar, but these will return a corresponding typed number
formatString sscanf: aString => collection
- formatString is a printf/scanf-like format string; reads items from aString and returns a collection (i.e. an Array) of scanned objects.
For example,'%d %x %f' sscanf: '1234 FF 3.1415'
will return an array-like collection with 3 elements, the integer 1234, the integer 255 and the float 3.14159.
- formatString is a printf/scanf-like format string; reads items from aString and returns a collection (i.e. an Array) of scanned objects.
formatString scanf: aStream => collection
- like above, but the elements will be read from a character stream
Truncation and Rounding[Bearbeiten]
aNumber truncated
=> Integer
- truncates towards zero
aNumber rounded
=> Number
- rounds up/down towards the nearest integer
aNumber ceiling
=> Number
- returns the next larger integer (unless aNumber is integral). I.e. truncates towards positive infinity.
aNumber floor
=> Number
- returns the next smaller integer (unless aNumber is integral). I.e. truncates towards negative infinity.
aNumber roundTo:
grid => Number
- rounds up/down towards the nearest multiple of grid. I.e. "1.284 roundedTo:0.1" yields "1.3".
aNumber truncateTo:
grid => Number
- truncates towards the nearest multiple of grid. I.e. "1.284 truncateTo:0.1" yields "1.2".
Conversion[Bearbeiten]
In certain situations, it may be desirable to convert explicitly to a particular type, for example when binary data has to be verified or filled into a byte-buffer.
aNumber asInteger
=> Integer
- truncates (i.e. same as "truncated")
aNumber asFloat
=> Float64
- generates double precision float; may generate +/- INF if the value cannot be represented as a double IEEE float (i.e. is out of range).
aNumber asFloatChecked
=> Float64 or error
- same as above, but generates an error if the value cannot be represented.
aNumber asShortFloat
=> Float32
- generates single precision float; may generate +/- INF if the value cannot be represented as a single IEEE float.
aNumber asShortFloatChecked
=> Float32 or error
- same as above, but generates an error if the value cannot be represented.
aNumber asLongFloat
=> Float80
- generates an extended precision float; may generate +/- INF if the value cannot be represented as an extended IEEE float.
aNumber asLongFloatChecked
=> Float80 or error
- same as above, but generates an error if the value cannot be represented.
aNumber asQDouble
=> QDouble
- generates a qDouble (from a float or integer)
aNumber asQuadFloat
=> QuadFloat
- generates a quadruple precision float (from a float or integer)
aNumber asOctaFloat
=> OctaFloat
- generates an octuple precision float (from a float or integer)
aNumber asFraction
=> Fraction
- generates a fraction (from a float)
aNumber asScaledDecimal:
scale => ScaledDecimal
- generates a scaled decimal which presents scale fractional digits
aNumber asFixedDecimal:
scale => FixedDecimal
- generates a fixed decimal which rounds on and presents scale fractional digits
aNumber asComplex
=> Complex
- generates a complex (with 0 as imaginary part, same as "nr + 0i")
Examples[Bearbeiten]
Square root of 2 with different precision:
nr := 2.0 sqrt. '%.30g' printf:{nr} -> '1.414213562373095101065700873732' (a float) '%.50g' printf:{nr} -> '1.41421356237309510106570087373256683349609375'
Be reminded that these floats (which are IEEE doubles) only provide 15 digits of accuracy ("Float decimalPrecision" returns 15).
More valid digits are returned by QDoubles ("QDouble decimalPrecision" returns 61):
nr := 2.0 asQDouble sqrt. '%.30g' printf:{nr} -> '1.41421356237309504880168872421' (roughly 200 bits precision) '%.50g' printf:{nr} -> '1.4142135623730950488016887242096980785696718753769' '%.100g' printf:{nr} -> '1.414213562373095048801688724209698078569671875376948073176679737988424424484343089516915416653038211'
or with octuple precision floats ("OctaFloat decimalPrecision" returns 71):
nr := 2.0 asOctaFloat sqrt. '%.30g' printf:{nr} -> '1.41421356237309504880168872421' (a quadruple precision float) '%.50g' printf:{nr} -> '1.4142135623730950488016887242096980785696718753769' '%.100g' printf:{nr} -> '1.41421356237309504880168872420969807856967187537694807317667973799073247801160833747418698891953623'
Finally, an arbitrary number of digits can be computed with LargeFloats (here 1000 bits for roughly 300 digits precision):
nr := (2.0 asLargeFloatPrecision:1000) sqrt. '%.30g' printf:{nr} -> '1.41421356237309504880168872421' '%.50g' printf:{nr} -> '1.4142135623730950488016887242096980785696718753769' '%.100g' printf:{nr} -> '1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573'
Printf Format Specifier[Bearbeiten]
Characters not escaped by a '%' are printed as-is. Following a '%' there can be:
- optional: '-' (POSIX refers to this as the <<flags>>)
- optional: positive number or '*' (POSIX: <<width>>)
- optional: period followed by positive number or * (POSIX: <<precision>>)
- optional: an h or l to indicate size of data (POSIX: <<length>>)
- required: character describing output behavior (POSIX: <<conversion specifier>>)
The format follows the official C-library printf formats; however, there were differences in the various printf implementations:
ANSI standards up through C99:
- more flags '+' ' ' '0' '#'
- more lengths 'L' 'hh' 'll' 'j' 'z' 't'
- more conversions 'F' 'a' 'A' 'n'
The POSIX specification of printf added:
- positional parameters to identify argument indices
- more flags (single quote)
- more conversions 'C' 'S'
- clarifications regarding corner cases and 'undefined behavior'
BSD implementations added:
- more lengths 'q'
- more conversions 'D' 'U' 'O'
glibc (GNU) added:
- more lengths 'Z'
- more conversions 'm'
Windows C Runtime (CRT) added:
- more lengths 'I' 'I32' 'I64' 'w'
glibc and CRT both added length 'Z'.
- glibc uses 'Z' for the length size_t.
- CRT uses Z as a conversion for length-prefixed strings.
The Smalltalk implementation takes the former approach, handling 'Z' in the same way as 'z'.
BSD and IBM C library both added 'D'.
- BSD uses D as a conversion, namely as an alias of 'ld'.
- IBM uses 'D' for the length for _Decimal64, a decimal floating point type,
- in accordance with ISO/IEC TR 24732.
The Smalltalk implementation takes the former approach.
The Smalltalk implementation also adds new conversions:
- 'b' and 'B' for binary (base-2) integer renderings
- 'y' and 'Y' for true/false and yes/no Boolean conversions
- 'J' for JSON
- 'T' and 'V' for JS typeof and valueOf inspection
- 'S' for store-string
- 'P' for print-string
Prefixes:
- ' ' fill with spaces
- '0' fill with zeros
- '+' print the sign
- '-' left justified
- '#' depends:
- %o, %x, %b: print base prefix
- %e always show decimal point
- %e, %E, %f, %g always show decimal point
Conversions (upper case same as lower case, except for xX):
- 'a' (not implemented) hex floating point exp form
- 'b' binary (base 2)
- 'c' character or (first char of string)
- 'd' integer
- 'e' base-10 floating point exp form (scientific)
- 'f' base-10 floating point decimal form (non-scientific)
- 'g' 'e' or 'f', whichever looks more appropriate (based on value)
- 'i' integer (alias for 'd')
- 'j' (not implemented) JSON format
- 'n' (not implemented) stores number of characters written so far into arg
- 'o' base-8 octal
- 'p' (not implemented) pointer
- 's' string
- 't' type (i.e. class name)
- 'u' (not implemented) unsigned (negative values are converted)
- 'v' (not implemented) store string
- 'x' base-16 hex
- 'X' base-16 hex upper case
Parameter selection (not implemented):
- <n>$ take n'th parameter
Dynamic width/precision (consumed in order as presented):
- "*" take width/parameter from next argument
Examples:
'|%d|' printf: { 123 } -> '|123|' '|%5d|' printf: { 123 } -> '| 123|' '|%-5d|' printf: { 123 } -> '|123 |' '|%s|' printf: { 'abc' } -> '|abc|' '|%5s|' printf: { 'abc' } -> '| abc|' '|%*s|' printf: { 5 . 'abc' } -> '| abc|' '|%f|' printf: { 1.234 } -> '|1.234|' '|%#f|' printf: { 1.234 } -> '|1.234000|'
'|%8f|' printf: { 1.234 } -> '| 1.234|' '|%*f|' printf: { 8 . 1.234 } -> '| 1.234|' '|%10f|' printf: { 1.234 } -> ' 1.234' '|%#10f|' printf: { 1.234 } -> ' 1.234000'
Negative width will fill at the right:
'|%5s|' printf: { 'abc' } -> '| abc|' '|%-5s|' printf: { 'abc' } -> '|abc |' '|%-*s|' printf: { 5 . 'abc' } -> '|abc |' '|%*s|' printf: { -5 . 'abc' } -> '|abc |' '|%-8f|' printf: { 1.234 } -> '|1.234 |' '|%*f|' printf: { -8 . 1.234 } -> '|1.234 |' '|%-*f|' printf: { 8 . 1.234 } -> '|1.234 |' '|%-*f|' printf: { -8 . 1.234 } -> '|1.234 |'
A Zero as fill character (only at the left):
'|%05s|' printf: { 'abc' } -> '|00abc|' '|%05d|' printf: { 123 } -> '|00123|'
Case of float-format character affects printing of Nan, Infinity and exponent separator:
'%f' printf: { 1.234 } -> '1.234000' '%F' printf: { 1.234 } -> '1.234000' '%e' printf: { 1.234 } -> '1.234e0' '%E' printf: { 1.234 } -> '1.234E0' '%f' printf: {Float NaN} -> 'nan' '%F' printf: {Float NaN} -> 'NAN' '%f' printf: {Float infinity} -> 'inf' '%F' printf: {Float infinity} -> 'INF' '%f' printf: {Float negativeInfinity} -> '-inf' '%F' printf: {Float negativeInfinity} -> '-INF' '%-F' printf: {Float infinity} -> '+INF' '%-F' printf: {Float negativeInfinity} -> '-INF' '% F' printf: {Float infinity} -> ' INF' '% F' printf: {Float negativeInfinity} -> '-INF'
Scanf Format Specifier[Bearbeiten]
The Smalltalk implementation adds new conversions:
Conversions (upper case same as lower case):
- 'b' binary (base 2)
- 'c' character or (first char of string)
- 'd' decimal
- 'e' float
- 'f' float
- 'g' float
- 'i' integer (alias for 'd')
- 'o' base-8 octal
- 's' string
- 'u' integer
- 'x' base-16 hex
- 'n' any number
Length prefix:
- 'h' with float formats: reads as ShortFloat
- 'L' with float formats: reads as LongFloat
Examples:
'%d %x' sscanf:'1234 ff00' -> OrderedCollection(1234 65280) '%d %s' sscanf:'1234 ff00' -> OrderedCollection(1234 'ff00') '%d %x %b' sscanf:'1234 ff00 1001' -> OrderedCollection(1234 65280 9)
('%f' sscanf:'1234') first -> 1234.0 (Float i.e. an IEEE double) ('%lf' sscanf:'1234') first -> 1234.0 (Float i.e. an IEEE double) ('%llf' sscanf:'1234') first -> 1234.0 (Float i.e. an IEEE double)
('%hf' sscanf:'1234') first -> 1234.0 (ShortFloat i.e. an IEEE single) ('%Lf' sscanf:'1234') first -> 1234.0 (LongFloat i.e. an IEEE extended) ('%LLf' sscanf:'1234') first -> 1234.0 (QDouble)