Binary to Decimal in Delphi 7 - delphi

I'm trying to do a simple console program where user input a binary string and he get a decimal number. I dont need to check if the binary string have something else than 0 or 1. I already managed to do decimal to binary but can't do it the other way.
I tried some code found on SO and Reddit but most of the time i got error I/O 105
Here's the dec to bin :
program dectobin;
{$APPTYPE CONSOLE}
uses
SysUtils,
Crt32;
var
d,a :Integer;
str :String;
begin
str:='';
Readln(a);
while a>0 do begin
d:=a mod 2;
str:=concat(IntToStr(d),str);
a:=a div 2;
end;
Writeln(str);
Readln;
end.```

Basics of positional number systems (PNS)
The number of unique digits in a PNS is its base (or radix)
The decimal system (base = 10) has ten digits, 0..9
The binary system (base = 2) has two digits, 0..1
The position of a digit in a number determines its weight:
the rightmost digit has a weight of units (1), (base)^0 (decimal 1, binary 1)
the second (from right) digit has a weight of (base)^1 (decimal 10, binary 2)
the third (from right) digit has a weight of (base)^2 (decimal 100, binary 4)
and so on ....
Note that the weight is always base * weight of previous digit (in a right to left direction)
General interpretation of a string of numbers in any positional number system
assign a variable 'result' = 0
assign a variable 'weight' = 1 (for (base)^0 )
repeat
read the rightmost (not yet read) digit from string
convert digit from character to integer
multiply it by weight and add to variable 'result'
multiply weight by base in prep. for next digit
until no more digits
After previous, you can use e.g. IntToStr() to convert to decimal string.

Related

LUA 5.4 - How to convert 64-bit numbers to hex

I wanted to convert numbers greater than 64 bits, including up to 256 bits number from decimal to hex in lua.
Example:
num = 9223372036854775807
num = string.format("%x", num)
num = tostring(num)
print(num) -- output is 7fffffffffffffff
but if I already add a single number, it returns an error in the example below:
num = 9223372036854775808
num = string.format("%x", num)
num = tostring(num)
print(num) -- error lua54 - bad argument #2 to 'format' (number has no integer representation)
Does anyone have any ideas?
I wanted to convert numbers greater than 64 bits, including up to 256 bits number from decimal to hex in lua.
Well that's not possible without involving a big integer library such as this one. Lua 5.4 has two number types: 64-bit signed integers and 64-bit floats, which are both to limited to store arbitrary 256-bit integers.
The first num in your example, 9223372036854775807, is just the upper limit of int64 bounds (-2^63 to 2^63-1, both inclusive). Adding 1 to this forces Lua to cast it into a float64, which can represent numbers way larger than that at the cost of precision. You're then left with an imprecise float which has no "integer representation" as Lua tells you.
You could trivially reimplement %x yourself, but that wouldn't help you extend the precision/size of floats & ints. You need to find another number representation and find or write a bigint library to go with it. Options are:
String representation: Represent numbers as hex- or bytestrings (base 256).
Table representation: Represent numbers as lists of numbers (base 2^x where x is < 64)

How to convert a floating point number to a string with max. 2 decimal digits in Delphi

How can I convert a floating point number to a string with a maximum of 2 decimal digits in Delphi7?
I've tried using:
FloatToStrF(Query.FieldByName('Quantity').AsFloat, ffGeneral, 18, 2, FS);
But with the above, sometimes more than 2 decimal digits are given back, ie. the result is: 15,60000009
Use ffFixed instead of ffGeneral.
ffGeneral ignores the Decimal parameter.
When you use ffGeneral, the 18 is saying that you want 18 significant decimal digits. The routine will then express that number in the shortest manner, using scientific notation if necessary. The 2 is ignored.
When you use ffFixed, you are saying you want 2 digits after the decimal point.
If you are wondering about why you sometimes get values that seem to be imprecise, there is much to be found on this site and others that will explain how floating-point numbers work.
In this case, AsFloat is returning a double, which like (most) other floating-point formats, stores its value in binary. In the same way that 1/3 cannot be written in decimal with finite digits, neither can 15.6 be represented in binary in a finite number of bits. The system chooses the closest possible value that can be stored in a double. The exact value, in decimal, is:
15.5999999999999996447286321199499070644378662109375
If you had asked for 16 digits of precision, the value would've been rounded off to 15.6. But you asked for 18 digits, so you get 15.5999999999999996.
If you really mean what you write (MAX 2 decimal digits) and does not mean ALWAYS 2 decimal digits, then the two code snippets in the comments won't give you want you asked for (they will return a string that ALWAYS has two decimal digits, ie. ONE is returned as "1.00" (or "1,00" for Format depending on your decimal point).
If you truly want an option with MAX 2 decimal digits, you'll have to do a little post-processing of the returned string.
FUNCTION FloatToStrMaxDecimals(F : Extended ; MaxDecimals : BYTE) : STRING;
BEGIN
Result:=Format('%.'+IntToStr(MaxDecimals)+'f',[F]);
WHILE Result[LENGTH(Result)]='0' DO DELETE(Result,LENGTH(Result),1);
IF Result[LENGTH(Result)] IN ['.',','] THEN DELETE(Result,LENGTH(Result),1)
END;
An alternative (and probably faster) implementation could be:
FUNCTION FloatToStrMaxDecimals(F : Extended ; MaxDecimals : BYTE) : STRING;
BEGIN
Result:=Format('%.'+IntToStr(MaxDecimals)+'f',[F]);
WHILE Result[LENGTH(Result)]='0' DO SetLength(Result,PRED(LENGTH(Result)));
IF Result[LENGTH(Result)] IN ['.',','] THEN SetLength(Result,PRED(LENGTH(Result)))
END;
This function will return a floating point number with MAX the number of specified decimal digits, ie. one half with MAX 2 digits will return "0.5" and one third with MAX 2 decimal digits will return "0.33" and two thirds with MAX 2 decimal digits will return "0.67". TEN with MAX 2 decimal digits will return "10".
The final IF statement should really test for the proper decimal point, but I don't think any value other than period or comma is possible, and if one of these are left as the last character in the string after having stripped all zeroes from the end, then it MUST be a decimal point.
Also note, that this code assumes that strings are indexed with 1 for the first character, as it always is in Delphi 7. If you need this code for the mobile compilers in newer Delphi versions, you'll need to update the code. I'll leave that exercise up to the reader :-).
i use this function in my application:
function sclCurrencyND(Const F: Currency; GlobalDegit: word = 2): Currency;
var R: Real; Fact: Currency;
begin
Fact:= power(10, GlobalDegit);
Result:= int(F*Fact)/Fact;
end;

Calculating ISIN checksum

HI I know there have been may question about this here but I wasn't able to find a detailed enough answer, Wikipedia has two examples of ISIN and how is their checksum calculated.
The part of calculation that I'm struggling with is
Multiply the group containing the rightmost character
The way I understand this statement is:
Iterate through each character from right to left
once you stumble upon a character rather than digit record its position
if the position is an even number double all numeric values in even position
if the position is an odd number double all numeric values in odd position
My understanding has to be wrong because there are at least two problems:
Every ISIN starts with two character country code so position of rightmost character is always the first character
If you omit the first two characters then there is no explanation as to what to do with ISINs that are made up of all numbers (except for first two characters)
Note
isin.org contains even less information on verifying ISINs, they even use the same example as Wikipedia.
I agree with you; the definition on Wikipedia is not the clearest I have seen.
There's a piece of text just before the two examples that explains when one or the other algorithm should be used:
Since the NSIN element can be any alpha numeric sequence (9 characters), an odd number of letters will result in an even number of digits and an even number of letters will result in an odd number of digits. For an odd number of digits, the approach in the first example is used. For an even number of digits, the approach in the second example is used
The NSIN is identical to the ISIN, excluding the first two letters and the last digit; so if the ISIN is US0378331005 the NSIN is 037833100.
So, if you want to verify the checksum digit of US0378331005, you'll have to use the "first algorithm" because there are 9 digits in the NSIN. Conversely, if you want to check AU0000XVGZA3 you're going to use the "second algorithm" because the NSIN contains 4 digits.
As to the "first" and "second" algorithms, they're identical, with the only exception that in the former you'll multiply by 2 the group of odd digits, whereas in the latter you'll multiply by 2 the group of even digits.
Now, the good news is, you can get away without this overcomplicated algorithm.
You can, instead:
Take the ISIN except the last digit (which you'll want to verify)
Convert all letters to numbers, so to obtain a list of digits
Reverse the list of digits
All the digits in an odd position are doubled and their digits summed again if the result is >= 10
All the digits in an even position are taken as they are
Sum all the digits, take the modulo, subtract the result from 0 and take the absolute value
The only tricky step is #4. Let's clarify it with a mini-example.
Suppose the digits in an odd position are 4, 0, 7.
You'll double them and get: 8, 0, 14.
8 is not >= 10, so we take it as it is. Ditto for 0. 14 is >= 10, so we sum its digits again: 1+4=5.
The result of step #4 in this mini-example is, therefore: 8, 0, 5.
A minimal, working implementation in Python could look like this:
import string
isin = 'US4581401001'
def digit_sum(n):
return (n // 10) + (n % 10)
alphabet = {letter: value for (value, letter) in
enumerate(''.join(str(n) for n in range(10)) + string.ascii_uppercase)}
isin_to_digits = ''.join(str(d) for d in (alphabet[v] for v in isin[:-1]))
isin_sum = 0
for (i, c) in enumerate(reversed(isin_to_digits), 1):
if i % 2 == 1:
isin_sum += digit_sum(2*int(c))
else:
isin_sum += int(c)
checksum_digit = abs(- isin_sum % 10)
assert int(isin[-1]) == checksum_digit
Or, more crammed, just for functional fun:
checksum_digit = abs( - sum(digit_sum(2*int(c)) if i % 2 == 1 else int(c)
for (i, c) in enumerate(
reversed(''.join(str(d) for d in (alphabet[v] for v in isin[:-1]))), 1)) % 10)

Conversion of bitstring to decimal in Erlang

I am trying to decode the bitstring to decimal value. For e.x I have these kind of bitstrings
<<96,64,112,153,9:4>>. I want to convert them to decimal values like you take four bits as a digit (96(01100000) --> 60( first four bits is 6, next four bits is 0) , 64 --> 40 and so on. The output would be 604070999. The last 9:4 represents that you consider 4 bits to represent.
Can anyone help in doing this function erlang.
If you have a binary rather than a bitstring (i.e., without the trailing 9:4 part), you can apply a hex conversion to each byte within a binary comprehension, then convert the resulting binary to an integer:
1> Bin = <<96,64,112,153>>.
<<96,64,112,153>>
2> binary_to_integer(<< <<(integer_to_binary(B,16))/binary>> || <<B:8>> <= Bin >>).
60407099
The same also works for your bitstring, taking 4 bits at a time instead of 8 in the comprehension:
3> Bits = <<96,64,112,153,9:4>>.
<<96,64,112,153,9:4>>
4> binary_to_integer(<< <<(integer_to_binary(B,16))/binary>> || <<B:4>> <= Bits >>).
604070999
But as #Hynek-Pichi-Vychodil points out in the comments, for the bitstring you don't need the integer_to_binary/2 call at all, but instead can convert each 4-bit digit to its corresponding character by adding $0, the literal for the character 0:
5> binary_to_integer(<< <<($0+B)>> || <<B:4>> <= Bits >>).
604070999

SetRoundMode(rmUp) and rounding "round" values like 10, results in 10,0001 how come?

This code:
SetRoundMode(rmUp);
Memo1.Lines.Add(CurrToStr(SimpleRoundTo(10)));
Results in 10,0001.
I simply don't get it.
I thought that rmUp would do something like, round 10,0001 to 11, but never 10 to 10,0001.
Can anyone explain why this happens?
Thanks.
SimpleRoundTo works like this:
Divide the input value by 10-x, where x is the number of decimal places to preserve in the result.
Add 0.5 to that product.
Truncate the sum.
Multiply by 10-x.
The result is a floating-point value. As with most floating-point values, the result will not be exact, even though in your case you start with an exact value. The number of decimal places specified for SimpleRoundTo is negative, so the divisor in step 1, for your example input, will ideally be 0.01. But that can't be represented exactly as a floating-point number, so when 10 / 0.01 is calculated in step 1, the result is not exactly 1000. The result in step 3 will be exactly 1000, though, so the inexactness of the division isn't important. The inexactness of the multiplication in step 4 is, though. That product won't be exact. It will be slightly higher than 10.
So SimpleRoundTo returns a slightly higher value, and since you've specified that rounding should go up, the conversion of the Extended result of SimpleRoundTo to the Currency input of CurrToStr results in exactly 10.0001.
Currency values are exact; they represent a fixed-point value, an integer scaled by four decimal places.
i'd use the Round( ) function if banker's rounding is ok. it returns an integer.
if you don't like banker's rounding you can use this:
// use this to not get "banker's rounding"
function HumanRound(X: Extended): integer;
// Rounds a number "normally": if the fractional
// part is >= 0.5 the number is rounded up (see RoundUp)
// Otherwise, if the fractional part is < 0.5, the
// number is rounded down
// RoundN(3.5) = 4 RoundN(-3.5) = -4
// RoundN(3.1) = 3 RoundN(-3.1) = -3
begin
// Trunc() does nothing except conv to integer. needed because return type of Int() is Extended
Result := Trunc(Int(X) + Int(Frac(X) * 2));
end;
my posting here is somewhat off-topic but still informative.
i looked into this at length since i needed to not be using banker's rounding. here are my findings. so far as i can see, this still doesn't get rid of banker's rounding
Value Meaning
rmNearest Rounds to the closest value.
rmDown Rounds toward negative infinity.
rmUp Rounds toward positive infinity.
rmTruncate Truncates the value, rounding positive numbers down and negative numbers up.
rmNearest // default
0.500 0
1.500 2
2.450 2
2.500 2
2.550 3
3.450 3
3.500 4
3.550 4
rmDown
0.500 0
1.500 1
2.450 2
2.500 2
2.550 2
3.450 3
3.500 3
3.550 3
rmUp
0.500 1
1.500 2
2.450 3
2.500 3
2.550 3
3.450 4
3.500 4
3.550 4
rmTrunc
0.500 0
1.500 1
2.450 2
2.500 2
2.550 2
3.450 3
3.500 3
3.550 3
uses
math, sysutils, clipbrd;
var
s:string;
procedure trythis(sMode:string);
procedure tryone(d:double);
begin
s:=s+Format('%1.3f %d%s',[d,Round(d),#13+#10]);
end;
begin
s:=s+#13#10+sMode+#13#10;
tryone(0.50);
tryone(1.50);
tryone(2.45);
tryone(2.50);
tryone(2.55);
tryone(3.45);
tryone(3.50);
tryone(3.55);
end;
begin
s:=inttostr(integer(GetRoundMode));
SetRoundMode(rmNearest);
trythis('nearest');
SetRoundMode(rmDown);
trythis('down');
SetRoundMode(rmUp);
trythis('up');
SetRoundMode(rmTruncate);
trythis('trunc');
clipboard.astext:=s;
end.
The return values from calculation SimpleToRound is also a Double and they can never be trusted on rounding. Truncate the value before converting it should do the work!
Memo1.Lines.Add(CurrToStr(Trunc(SimpleRoundTo(10))));
The Ceil() : Integer function should give you the answer you want for values > 0. If < 0 you may need to use floor() instead, depending on desired behaviour.

Resources