Repository navigation
CInt96
Home › All Categories › sys/win › sys/win/com › CInt96
Stores a 96-bit signed integer in a COM DECIMAL and does arithmetic on it.
CInt96 holds whole numbers from −(2⁹⁶ − 1) to 2⁹⁶ − 1, about ±7.9 × 10²⁸, far beyond the
±9.2 × 10¹⁸ of a longint. The value lives in the public
field m_int96, a DECIMAL with a scale of 0: a 96-bit magnitude and a separate sign. The
arithmetic is done by the Automation decimal functions (VarDecAdd, VarDecMul …); the bitwise
operators turn the value into 96-bit two's complement, work on that and turn it back.
What to keep in mind:
-
Literals. A number that fits in a
longintorulongintcan be assigned directly. Anything larger comes in as a string literal when the variable is created, as in the Example, or withwstr()when it is assigned (Let). -
Errors are quiet. Nothing raises an error. On failure the operation stores the
HRESULTinGetLastError(), and a binary operator such as+or*returns its left operand unchanged: an overflow or a division by zero leaves you with the first number. Clear the code withSetLastError( 0 )before an operation whose failure you want to see, and read it straight after: converting aCInt96to text (printing it) resets it. -
Rounding.
/rounds down, toward negative infinity:-17 / 5is −4.modtruncates toward zero, so-17 mod 5is −2 and the two do not add back up for negative numbers. -
Equality. The
=comparison is not available outside the module; compare withnot ( a <> b ). The other comparisons are. -
Text. A
CInt96prints as it is and converts to astring.
Nothing has to be freed.
#import "sys/win"
#import "sys/win/com"
using win, comFinds the largest factorial that fits, works with a value beyond 64 bits and shows how division
and mod round:
#import "sys/win"
#import "sys/win/com"
using win, com
' The largest factorial that fits in 96 bits
dim f as CInt96 = 1
dim n as long = 1
do
SetLastError( 0 )
dim nxt as CInt96 = f * CInt96( n + 1 )
if GetLastError() <> 0 then exit do ' overflow: nxt is f unchanged
f = nxt
n += 1
loop
print n; "! = "; f
' Values beyond 64 bits come in as text
dim big as CInt96 = "79228162514264337593543950335"
print "largest: "; big
print "2 ^ 95 = "; CInt96( 1 ) shl 95
' Division rounds down; mod keeps the sign of the dividend
print CInt96( -17 ) / CInt96( 5 ), CInt96( -17 ) mod CInt96( 5 )It prints:
27! = 10888869450418352160768000000
largest: 79228162514264337593543950335
2 ^ 95 = 39614081257132168796771975168
-4 -2
| Member | Does |
|---|---|
| Constructor | Creates a CInt96 from a number, a string, a DECIMAL or another CInt96. |
| Destructor | Does nothing; there is nothing to free. |
| Let | Assigns a number, a string, a DECIMAL or another CInt96. |
| Cast | Converts to CURRENCY, VARIANT or string. |
| Operator +=, -=, *=, /= | Adds, subtracts, multiplies or divides in place. |
| Operator mod= | Replaces the value with the remainder of a division. |
| Operator and=, or=, xor=, imp=, eqv= | Combines the bits in place. |
| Operator shl=, shr= | Shifts in place. |
| Sign | Returns the sign byte of the DECIMAL. |
| IsSigned, IsUnsigned | Tells whether the value is negative. |
| ToVar | Returns the value as a VARIANT. |
constructor
constructor( byref cSrc as CInt96 )
constructor( byref decSrc as DECIMAL )
constructor( byval nInteger as longint )
constructor( byval nUInteger as ulongint )
constructor( byref wszSrc as wstring )- With no argument the value is 0.
- From a
DECIMALwith a fractional part, the fraction is dropped by rounding down (VarDecInt): 12.75 gives 12, −12.75 gives −13. - From a string the text is parsed as a whole number; surrounding spaces are ignored. A string
containing a
.is refused withE_INVALIDARG, and text that is not a number givesDISP_E_TYPEMISMATCH; either way the value stays 0 andGetLastError()holds the code. - From
longintandulongintevery value of those types is exact.
| Parameter | Meaning |
|---|---|
cSrc |
Another CInt96 to copy. |
decSrc |
A DECIMAL. |
nInteger, nUInteger
|
A 64-bit number. |
wszSrc |
The number as text. |
Example
dim a as CInt96 = 123456789012345678ll
dim b as CInt96 = "79228162514264337593543950335"
print a; " "; bMicrosoft Learn: VarDecFromStr
destructorDoes nothing: a CInt96 holds no resources.
Example
scope
dim n as CInt96 = 42
end scopeoperator let( byref cSrc as CInt96 )
operator let( byref decSrc as DECIMAL )
operator let( byval n as longint )
operator let( byval u as ulongint )
operator let( byref s as wstring )Assigns a new value, converted as the matching Constructor does: a DECIMAL
with a fraction is rounded down, a string with a . is refused with E_INVALIDARG and leaves
the value as it was.
Pass text as a wide string. A narrow string literal assigned with = (n = "100") currently
reaches the string form unconverted: it fails with DISP_E_TYPEMISMATCH and the value stays as
it was. Write n = wstr( "100" ), or n = CInt96( "100" ). Creating a CInt96 from a narrow
literal (dim n as CInt96 = "100") is not affected.
Example
dim n as CInt96
n = 5
n = wstr( "100000000000000000000000" )
print noperator cast() as CURRENCY
operator cast() as VARIANT
operator cast() as string- To
CURRENCY: the value scaled by 10 000, asCURRENCYstores it (12345 becomes anint64of 12345 × 10 000). A value beyond the range ofCURRENCYgives 0, withDISP_E_OVERFLOWinGetLastError(). - To
string: the number as decimal text, with a leading-when negative. This is whatprintuses. - To
VARIANT: see ToVar, which it matches, including itsvtof 0.
Example
dim n as CInt96 = -42
dim s as string = n
dim cy as CURRENCY = CInt96( 12345 )
print "["; s; "]"; cy.int64 \ 10000 ' [-42] 12345Microsoft Learn: VarBstrFromDec
operator +=( byref int96 as CInt96 )
operator -=( byref int96 as CInt96 )
operator *=( byref int96 as CInt96 )
operator /=( byref cOperand as CInt96 )Add, subtract, multiply or divide the value in place. /= rounds the quotient down, toward
negative infinity. On overflow or division by zero GetLastError() holds the HRESULT
(DISP_E_OVERFLOW, DISP_E_DIVBYZERO).
Example
dim n as CInt96 = 100
n += CInt96( 5 )
n /= CInt96( 7 )
print n ' 15Microsoft Learn: VarDecAdd
operator mod=( byref rhs as CInt96 )Replaces the value with the remainder of dividing it by rhs, truncating the quotient toward
zero: the result has the sign of the value, so -17 mod= 5 gives −2. Dividing by 0 sets
DISP_E_DIVBYZERO in GetLastError() and leaves the value alone.
Example
dim n as CInt96 = -17
n mod= CInt96( 5 )
print n ' -2Microsoft Learn: VarDecFix
operator and=( byref rhs as CInt96 )
operator or=( byref rhs as CInt96 )
operator xor=( byref rhs as CInt96 )
operator imp=( byref rhs as CInt96 )
operator eqv=( byref lhs as CInt96 )Combine the bits of the value with those of the operand in place, both taken as 96-bit two's
complement numbers: and, or and xor as usual, imp as ( not a ) or b, eqv as
not ( a xor b ). So 5 and= 3 gives 1, -5 xor= 2 gives −7, 5 imp= 3 gives −5.
Example
dim n as CInt96 = 5
n or= CInt96( 3 )
print n ' 7operator shl=( byval nBits as uinteger )
operator shr=( byval nBits as uinteger )shl= multiplies the value by 2 nBits times; when it overflows it stops there, with the value
doubled as far as it went and DISP_E_OVERFLOW in GetLastError(). shr= divides by 2 nBits
times, rounding down each time, which is an arithmetic shift: -100 shr= 3 gives −13 and
-1 shr= 100 stays −1. Both take time in proportion to nBits.
Example
dim n as CInt96 = 7
n shl= 4
print n ' 112function Sign() as ubyteReturns the sign byte of the DECIMAL: 0 for zero and positive values, &h80 (128) for
negative ones.
Returns 0 or 128.
Example
print CInt96( -5 ).Sign ' 128function IsSigned() as boolean
function IsUnsigned() as booleanIsSigned is true for a negative value; IsUnsigned is true for zero and positive values.
Returns the test result.
Example
dim n as CInt96 = -42
print n.IsSigned, n.IsUnsigned ' true falsefunction ToVar() as VARIANTMeant to return the value as a VT_DECIMAL variant. The type field of a VARIANT shares its
memory with the first, reserved field of a DECIMAL, and ToVar sets the type before copying the
decimal in, so the variant comes back with vt = 0 (VT_EMPTY) and the number in decVal.
Set vt to VT_DECIMAL afterwards to use it.
Returns a VARIANT holding the number in decVal.
Example
dim v as VARIANT = CInt96( 7 ).ToVar()
v.vt = VT_DECIMAL
print v.decVal.Lo32 ' 7| Function | Does |
|---|---|
| Operator +, -, *, / | Adds, subtracts, negates, multiplies and divides. |
| Mod | Returns the remainder of a division. |
| And, Or, Xor, Not, Imp, Eqv | Combines or inverts the bits. |
| Shl, Shr | Shifts left or right. |
| Operator <>, <, >, <=, >= | Compares two values. |
| Abs | Returns the absolute value. |
| Operator * (address) | Returns the address of the DECIMAL. |
| _Bits96_ToTwos | Turns a DECIMAL into three 32-bit two's complement words. |
| _Bits96_FromTwos | Turns three two's complement words back into a DECIMAL. |
operator +( byref int961 as CInt96, byref int962 as CInt96 ) as CInt96
operator -( byref int961 as CInt96, byref int962 as CInt96 ) as CInt96
operator -( byref int96Src as CInt96 ) as CInt96
operator *( byref int961 as CInt96, byref int962 as CInt96 ) as CInt96
operator /( byref int96Src as CInt96, byref cOperand as CInt96 ) as CInt96The four operations, and unary minus. / rounds the quotient down, toward negative infinity
(-17 / 5 is −4). On overflow or division by zero the result is the left operand unchanged
and GetLastError() holds the HRESULT.
Returns the result.
Example
dim a as CInt96 = "40000000000000000000000000000"
SetLastError( 0 )
dim b as CInt96 = a + a
if cast( HRESULT, GetLastError() ) = DISP_E_OVERFLOW then print "overflow, b = a"GetLastError() returns a DWORD; cast it to HRESULT before comparing it with an HRESULT
constant, which is negative.
Microsoft Learn: VarDecMul
operator mod( byref lhs as CInt96, byref rhs as CInt96 ) as CInt96Returns the remainder of lhs / rhs with the quotient truncated toward zero, so the remainder
has the sign of lhs: -5 mod 3 is −2, 5 mod -3 is 2. Dividing by 0 returns lhs and sets
DISP_E_DIVBYZERO in GetLastError().
Returns the remainder.
Example
print CInt96( 17 ) mod CInt96( 5 ) ' 2operator and( byref lhs as CInt96, byref rhs as CInt96 ) as CInt96
operator or( byref lhs as CInt96, byref rhs as CInt96 ) as CInt96
operator xor( byref lhs as CInt96, byref rhs as CInt96 ) as CInt96
operator not( byref value as CInt96 ) as CInt96
operator imp( byref lhs as CInt96, byref rhs as CInt96 ) as CInt96
operator eqv( byref lhs as CInt96, byref rhs as CInt96 ) as CInt96Bitwise operations on the 96-bit two's complement form of the values: 5 and 3 is 1, 5 or 3
is 7, 5 xor 3 is 6, not 0 is −1, 5 imp 3 is −5 and 5 eqv 3 is −7.
Returns the result.
Example
print CInt96( 5 ) and CInt96( 3 ), not CInt96( 0 ) ' 1 -1operator shl( byref value as CInt96, byval nBits as uinteger ) as CInt96
operator shr( byref value as CInt96, byval nBits as uinteger ) as CInt96shl returns value × 2^nBits; when that overflows it returns value unchanged and sets
DISP_E_OVERFLOW in GetLastError(). shr returns value / 2^nBits rounded down, an
arithmetic shift: -3 shr 1 is −2 and -1 shr 100 is −1. Both work by repeated doubling or
halving.
Returns the shifted value.
Example
print CInt96( 1 ) shl 95, CInt96( -100 ) shr 3 ' 2^95, then -13operator <>( byref int961 as CInt96, byref int962 as CInt96 ) as boolean
operator <( byref int961 as CInt96, byref int962 as CInt96 ) as boolean
operator >( byref int961 as CInt96, byref int962 as CInt96 ) as boolean
operator <=( byref int961 as CInt96, byref int962 as CInt96 ) as boolean
operator >=( byref int961 as CInt96, byref int962 as CInt96 ) as booleanCompare two values numerically. The = operator is private to the module: write
not ( a <> b ) to test for equality.
Returns the result of the comparison.
Example
dim a as CInt96 = 4
dim b as CInt96 = 4
if not ( a <> b ) andalso a <= b then print "equal"Microsoft Learn: VarDecCmp
operator abs( byref c96 as CInt96 ) as CInt96Returns the absolute value.
Returns the value without its sign.
Example
print abs( CInt96( -42 ) ) ' 42Microsoft Learn: VarDecAbs
operator *( byref int96 as CInt96 ) as DECIMAL ptrReturns the address of m_int96, for a function that reads or writes a DECIMAL. A value
written there should keep a scale of 0.
Returns a pointer to the DECIMAL.
Example
dim n as CInt96 = -42
dim pd as DECIMAL ptr = *n
print pd->Lo32, pd->sign ' 42 128sub _Bits96_ToTwos( byref d as DECIMAL, byref w0 as ulong, byref w1 as ulong, byref w2 as ulong )Writes the 96 bits of a DECIMAL with a scale of 0 into three words, low to high, as a two's
complement number: a negative value is complemented and incremented. The bitwise operators are
built on it. The scale is not looked at.
| Parameter | Meaning |
|---|---|
d |
The decimal. |
w0, w1, w2
|
Receive the low, middle and high 32 bits. |
Example
dim as ulong w0, w1, w2
_Bits96_ToTwos( CInt96( -1 ).m_int96, w0, w1, w2 )
print hex( w0 ), hex( w1 ), hex( w2 ) ' FFFFFFFF FFFFFFFF FFFFFFFFsub _Bits96_FromTwos( byval w0 as ulong, byval w1 as ulong, byval w2 as ulong, byref d as DECIMAL )The reverse of _Bits96_ToTwos: reads three words as a 96-bit two's complement
number, taking the top bit of w2 as the sign, and stores it in d with a scale of 0.
| Parameter | Meaning |
|---|---|
w0, w1, w2
|
The low, middle and high 32 bits. |
d |
Receives the decimal. |
Example
dim d as DECIMAL
_Bits96_FromTwos( &hFFFFFFFE, &hFFFFFFFF, &hFFFFFFFF, d )
dim n as CInt96 = d
print n ' -2- sys/win/com
-
DVARIANT for
VARIANTvalues - COM procedures
- Microsoft Learn: DECIMAL structure
tiko-lang · Home · Feature Index · Keyword Index · License
FreeBASIC manual pages reproduced under the GNU FDL 1.3.
- Home
- What Is tiko-lang
- Quick Start
- Installing on macOS
- Debugging
- Feature Index
- Compatibility
- FAQ
- AI Cheatsheet
- Generics
- Interfaces
- For Each
- Iterators
- Tuples
- Array Results
- Defer
- Lambdas
- Block Strings
- Partial Types
- String Slices
- Embed
- Typed Variadics
- C Header Import
- Foreign Library Linking
- UString
- Fixed-Width Types
- Nullptr
- String Library
- Format
- Array
- Map
- Set
- LinkedList
- OrderedMap
- OrderedSet
- Sorting
- Optional
- Result
- Smart Pointers
- Date and Time (Chrono)
- Time Zones
- Filesystem
- File Streams
- Config (INI and TOML)
- Codec
- Hash
- UUID
- OS
- Process
- Net
- HTTP and TLS
- Math Library
- Finance
- Logging
- Terminal TUI Library
- PsControls
- tkControls
- sys/win
- Goroutines and Channels
- LLVM Backend
- tiko build
- TIKO_COMPILER
- Variable Declarations
- Standard Data Types
- User Defined Types
- Procedures
- Operators
- Control Flow Statements
- Converting Data Types
- Array Functions
- String Functions
- Mathematical Functions
- Bit Manipulation
- Date and Time Functions
- File I/O Functions
- Console Functions
- User Input (Runtime Library)
- User Input Functions (Graphics Library)
- Screen Functions
- 2D Drawing Functions
- Graphics Library Reference
- Graphics Keyword List
- Memory Functions
- Threading Support Functions
- Error Handling Functions
- Operating System Functions
- Preprocessor
- Intrinsic Defines
- Miscellaneous Keywords
- Modularizing