I woke up this morning with a brain wave (a rare event for me), I realised that although my StringMap library can work with large numbers, it does of course return the answer as a string.
And I thought that someone might actually want that result as a value rather than a string.
So I've created a new routine called SMVal that takes a string such as "4294967295" Hex value FFFF FFFF, and returns the value 4294967295.
The return value is a UINT type variable called say... MyValue.
If I declare a variable X as INT and then say X = MyValue, X becomes -1.
Why is that exactly, and what's the difference between the two types of variables?
I've read the help file and the only difference stated is one is signed and the other unsigned.
I've also found 4294967295 is the largest number these variable types can handle, am I correct on this?
Thanks,
Andy.
UINT stands for unsigned integer
this means there is no bit used to designate polarity so you can only have positive numbers
therefore the number range is from 0 to 4294967295
INT stands for signed integer
this means there is a bit used to designate polarity and it is the most significant bit
when it is set the number is negative
that is why when you take 4294967295 and put it in a INT type variable it becomes -1
the range of an INT is â€"2147483648 to 2147483647
The same sort of thing happens with a CHAR (unsigned) 0-255 and
SCHAR (signed) -127 to 127
Hope that helps
Perfect - the penny drops for Int's and Uint's!
But that leads me to INT64 and UINT64, is the limit the same for them too?
I only ask because Int and Uint are 4 bytes, Int64 and Uint64 are 8 bytes.
Thanks,
Andy.
Int64 and Uint64 work exactly the same way
Int64: -9223372036854775808 to 9223372036854775807
Uint64: 0 to 18446744073709551615
Andy
thanks to you those numbers will now be in the next release of the help manual
Larry and all,
I did some testing this morning, and these details should be of interest to all...
Maths operations using +, - , * ----- maximum return value 4294967295
Maths operations using / ----- maximum return value 2147483647
STR$ acts like an Int ----- maximum return value 2147483647
VAL ----- maximum return value 18446744073709537000
GETCONTROLTEXT ----- maximum return value - none as far as I can see.
HEX$ ----- maximum return value 4294967295
ABS ----- maximum return value 2147483648 (Hex 8000 0000)
So,
You although may have a number 4294967295, the maximum number str$ can use is 2147483647
If you use Uint64 and have the number 4294967299 and use - (minus) to subtract 1 in a loop, the return value will be incorrect until you get down to 4294967295, and then it's fine.
If you have the number 4294967291 and use + (add) to add 1 in a loop, the return value will be fine up to and including 4294967295, after that the numbers are incorrect.
If you use * (multiply), that's fine as long as the result is less than or equal to 4294967295.
If you use / (divide), as long as the number is less than or equal to 2147483647 it will work, however if the number is bigger i.e. 2147483648 - it won't work.
Thanks,
Andy.
are you sure about the HEX$ value? it's suppose to work with INT64
also, I don't see any negative values anywhere (excluding ABS of course)
I've had another look, and this is what I've found....
If you make x an Int64 - Hex$ returns 16 F's for 4294967295 (wrong).
If x is an Uint - Hex$ returns 8 F's (correct)
If x is an Uint64 - Hex$ returns 16 F's (wrong).
And I've only tested on positive numbers so far.
This is why for Dwords in the registry I can work out the decimal value of the entry, but for Qwords (double the size of Dwords) no I can't, only if they have a decimal value is up to and no greater than FFFF FFFF, beyond that I'm lost.
Andy.
The PRINT command...
Althought Uint64 can be 0 to 18446744073709551615, if I try and print x, where x = 12345678901
I get the wrong number printed in a console program.
If x = 1234567890, then it prints 1234567890.
So, is x set correctly as 12345678901 or larger, or is it the print command just not displaying the correct number?
If I make x DOUBLE, then it prints 12345678901 or larger....
If I make x UINT64, and set x to 12345678901 or larger, and make y DOUBLE and say y = x... it doesn't print correctly again.
So after typing this, it looks like UINT64's have the problem?
My main question is how can I make sure a DOUBLE has .00 included in it? - I am working on a routine to convert large numbers to strings, which it now does, however, on a large number I have to make sure there is .00 on the end.
Example
Double D
D = 12345678901234.00 - works
D = 12345678901234 - does not.
Is this a Job for _printf?, and if so how do I use it?
Thanks,
Andy.
I have also found that as long as a unit64 is assigned a number <= 2147483647 you can use the + operator to add to it (as long as each addition is <= 2147483647).
e.g.
uint64 fVar = 0
for y = 1 to 80000000
fVar += 2147483647
next y
However, if you want to assign a number directly to a uint / double, and it is greater than 2147483647, you must add .00 to it
i.e. fVar = 744073709551615.00
openconsole
uint64 fVar = 0
fVar += 744073709551615.00
print
print
print " Number ",fVar
waitcon
end
So the question remains .....
How do I add a .00 to a double / uint64 ???
And isn't trying to add .00 to a uint a contradiction in terms ???
Thanks,
Andy.
Andy,
Try PRINT USING.
Bill
Bill,
That's a good try, but the number is too big for both USING and SETPRECISION commands.
Andy.
Attached is an example of how to convert a large number to a string.
The .lib file goes in your libs folder, and the .inc file goes in your include folder, then you can compile the program.
Although I'm still puzzled as to why a number larger than 2147483647 needs .00 on the end to be directly assigned to a double variable.
Thanks,
Andy.
Andy,
Maybe I missed something. Why are you needing .00 at the end of such large numbers? What kind of monies program are you working on that requires that much?
Bill
Bill,
I'm simply trying to set a double variable like this
double d
d = 2147483648 (does not work)
but you can only do it up to the number 2147483647
d = 2147483647 (works)
If the number is greater than 2147483647 you have to do it this way:
d = 2147483648.00 (works)
I'm simply trying to write my own version of str$ which can copy with larger numbers than str$ that's all.
Andy.
Quote from: Andy on May 19, 2016, 08:43:29 AM
Bill,
I'm simply trying to set a double variable like this
double d
d = 2147483648 (does not work)
but you can only do it up to the number 2147483647
d = 2147483647 (works)
If the number is greater than 2147483647 you have to do it this way:
d = 2147483648.00 (works)
I'm simply trying to write my own version of str$ which can copy with larger numbers than str$ that's all.
Andy.
Compiler defaults numeric literals without decimal as INT and numeric literals with decimal part as DOUBLE. You need to use numeric modifiers, check
Constants and Literals topic from the manual.
Jalih,
That's another good attempt, however I would still need to add something to the end of the number such as buq or .00 etc.
So the question still remains, how do you add something to a number when you do not know what that number is?
Thanks anyway,
Andy.
Quote from: Andy on May 20, 2016, 01:35:26 AM
Jalih,
That's another good attempt, however I would still need to add something to the end of the number such as buq or .00 etc.
So the question still remains, how do you add something to a number when you do not know what that number is?
Why do you feel the need to add something to a number? Numeric modifiers are only needed for numeric literals, also known as numeric constants. Compiler knows how to handle number in variable just fine based on it's type.
Jalih,
All my testing to date shows, that no matter how you modify a number, if the number is greater than 2147483647 it just does not work unless it has .00 on the end.
If you start with a number < = 2147483647 that's fine.
If you add to it and the number <= 2147483647 that's fine.
If you start with a number (or add to it) and the number is > 2147483647 it does not work.
I'm simply trying to turn a large number into a string, something that str$ cannot do above 2147483647.
I've been working on my library called StringMap, it started with the idea of working with strings and it has nearly 300 functions that would take someone a lot of coding to do, and it takes the work out of it for you.
I noticed the limit of str$, and that's why I'm trying to break that limit.
BTW, It's nice to see new members - welcome!
Thanks,
Andy.
Quote from: Andy on May 20, 2016, 09:37:10 AM
I noticed the limit of str$, and that's why I'm trying to break that limit.
How about using C library, something like:
double i
i = 2147483648.0
print MySTR$(i)
do:until inkey$ <> ""
SUB MySTR$(double d), string
DECLARE CDECL EXTERN _sprintf(buf as STRING, format as STRING, ...),INT
string s
_sprintf(s, "%.2f", d)
RETURN s
ENDSUB
You could also probably define function parameter as ANYTYPE and handle needed conversion based on type of the variable.
I've been looking at the C functions to try and get past this....
If you use your code it works because i is set to 2147483648.0 (with a .0), if you take the .0 away it doesn't work.
i = 2147483648
openconsole
print MySTR$(i)
do:until inkey$ <> ""
waitcon
end
SUB MySTR$(double d), string
DECLARE CDECL EXTERN _sprintf(buf as STRING, format as STRING, ...),INT
string s
_sprintf(s, "%.2f", d)
RETURN s
ENDSUB
So problem 1 is if the number is > 2147483647 you need the .0
problem 2 is that if you add to the previous number and it is > 2147483647 you also need the .0 added to it.
I've now managed to take any number from 0 to 4294967295 inclusive and turn it into a string.
So now I have to work on numbers bigger than 4294967295.... that's the next challenge.
Attached is the program, as always .lib to your IWB's libs folder, .inc to your IWB's include folder (both found in C:\Program Files\IWBDev).
Thanks,
Andy.
:)
Andy,
Just a little off topic question...
Do you ever sleep?
Egil
Egil,
QuoteDo you ever sleep?
I'm one of these people that usually get up around 5.30am, I do keep an eye on what's being posted just in case it may come in useful, but yes I do sleep, I'm not yet like the Terminator, just a dog with a bone when I get into something - I can't leave it! ;D
Andy.
Quotejust a dog with a bone when I get into something - I can't leave it!
Just like me, but I usually fiddle with my radios that early... ;D
Quote from: Andy on May 21, 2016, 05:38:25 AM
So now I have to work on numbers bigger than 4294967295.... that's the next challenge.
With little inline assembly, using the FPU to store number as packed BCD number and then converting from the packed BCD format to a null-terminated alphanumeric string gives you 18 digits precision...
I was also coming to the conclusion that assembly might be needed at this point.
Assembly was the first language I was shown at school when I was 13, and I touched it again at university - however I cannot remember now how to program in it.
Guess this could take a long time to get past this point - unless someone can help. ???
Thanks,
Andy.
:)
Quote from: Andy on May 23, 2016, 10:09:25 PM
Assembly was the first language I was shown at school when I was 13, and I touched it again at university - however I cannot remember now how to program in it.
Here is my first attempt for using FPU and BCD numbers to replace STR$...
int64 i
i = -123456789012345678q 'Negative number with 18 digits
string s
_asm
segment .data
num dt 0.0
segment .text
push esi
push edi
finit
fild qword[$i]
fbstp [num]
lea esi,[num+9]
lea edi,[$s]
mov eax, 0
fwait
mov al, [esi]
dec esi
or al, al
jns @@1
mov al,'-'
stosb
@@1:
mov ecx, 8
@@2:
mov al, [esi]
dec esi
or al,al
jnz @@3
dec ecx
jnz @@2
mov al, "0"
stosb
jmp done
@@3:
test al, 0f0h
jz digit2
digit1:
ror ax, 4
add al, 30h
stosb
shr ax, 12
digit2:
add al, 30h
stosb
mov al, [esi]
dec esi
jz done
digit12:
mov ah, al
shr al, 4
and ah, 0fh
add ax, 3030h
stosw
mov al, [esi]
dec esi
dec ecx
jnz digit12
done:
mov al, 0
stosb
pop edi
pop esi
_endasm
print s
do:until inkey$ <> ""
Wow - goes right over my head! But well done!
Brian
hello jalih
your program does not work with the full range of int64, I imagine it would take some effort to make it work as fbstp only outputs 18 digits.
Jalih,
I like the attempt!
However, as I've said before you cannot push a number larger than 18446744073709551615 (16 F's) to a uint64, It's too big.
And in any case, how on earth could you "add" a letter to a number?
What's my obsession with the number 18446744073709551615? - it represents the largest value a qword can have in the windows registry 0xFFFFFFFFFFFFFFFF.
However you may want to work with a number larger than 18446744073709551615 and then +, -, *, / will not work.
We need C's equivalent of a long or long long variable to work with such large numbers.
If you want to work with numbers greater than 18446744073709551615, you need to use my StringMap library, here you have +, -, *, / functions, but it does however need the number as a string, and returns a string for any maths operations used as the result - that's the best I can do, and it took me a very very long time to write these functions (so you don't have to).
Thanks,
Andy.
:)