i have hexdecimal data i have to convert into 64 Signed Decimal data ..so i thought have follwoing step like this.
1.hexadecimal to binary,
instead of writing my own code conversion i m using code given in this link http://necrobious.blogspot.com/2008/03/binary-to-hex-string-back-to-binary-in.html
bin_to_hexstr(Bin) ->
lists:flatten([io_lib:format("~2.16.0B", [X]) ||
X <- binary_to_list(Bin)]).
hexstr_to_bin(S) ->
hexstr_to_bin(S, []).
hexstr_to_bin([], Acc) ->
list_to_binary(lists:reverse(Acc));
hexstr_to_bin([X,Y|T], Acc) ->
{ok, [V], []} = io_lib:fread("~16u", [X,Y]),
hexstr_to_bin(T, [V | Acc]).
2.binary to decimal,
how to achieve this part.?
or any other way to achieve the hexdecimal -> 64 Signed Decimal data
thanx in advance
To convert an integer to a hex string, just use erlang:integer_to_list(Int, 16). To convert back, use erlang:list_to_integer(List, 16). These functions take a radix from 2 to 36 I believe.
If you want to convert binaries to and from hex strings you can use list comprehensions to make it tidier:
bin_to_hex(Bin) -> [ hd(erlang:integer_to_list(I, 16)) || << I:4 >> <= Bin ].
hex_to_bin(Str) -> << << (erlang:list_to_integer([H], 16)):4 >> || H <- Str >>.
To convert an integer to a hex string containing a 64 bit signed integer, you can now do:
Int = 1 bsl 48, HexStr = bin_to_hex(<<Int:64/signed-integer>>),
Bin = hex_to_bin(HexStr), <<RoundTrippedInt:64/signed-integer>> = Bin,
Int =:= RoundTrippedInt.
What about this approach?
hex2int(L) ->
<< I:64/signed-integer >> = hex_to_bin(L),
I.
int2hex(I) -> [ i2h(X) || <<X:4>> <= <<I:64/signed-integer>> ].
hex_to_bin(L) -> << <<(h2i(X)):4>> || X<-L >>.
h2i(X) ->
case X band 64 of
64 -> X band 7 + 9;
_ -> X band 15
end.
i2h(X) when X > 9 -> $a + X - 10;
i2h(X) -> $0 + X.
Related
I want to convert a given integer into a base 4 string. For eg : In scala,
var str: String = Integer.toString(10, 4)
gives the output "22" ie 2*(4^1) + 2*(4^0) = 10
Im having difficulty doing this in F#. Any help is appreciated
let intToDigits baseN value : int list =
let rec loop num digits =
let q = num / baseN
let r = num % baseN
if q = 0 then
r :: digits
else
loop q (r :: digits)
loop value []
254
|> intToDigits 16
|> List.fold (fun acc x -> acc + x.ToString("X")) ""
|> printfn "%s"
254
|> intToDigits 4
|> List.fold (fun acc x -> acc + x.ToString()) ""
|> printfn "%s"
This outputs FE for the base-16 conversion and 3332 for the base-4 conversion. Note that ToString("X") works for up to base 16, so it could be used for the base-4 conversion too.
I adapted this int based solution from Stuart Lang's bigint example (which uses bigint.DivRem rather than integer operators).
Part of testing, I have to load massive CSV files (200+mb each) and I'm trying to cut down the load time since this is adding up.
As the CSV files are all floating point numbers, I tried to see if I could speed that up.
One important point: I do NOT need precision beyond 5 digits after the comma. The code I post here parses it anyways to give a fair comparison to .NET's parser, but any shortcut that preserves that precision is good.
The code I came up with:
open System
open System.Diagnostics
[<EntryPoint>]
let main _ =
let r = Random()
let numbers =
seq {
for _ in 0 .. 10000000 do
let n = (1000. * r.NextDouble()) - 500.
yield (n, sprintf "%.8f" n)
}
|> Seq.toList
let parseString (number: string) : double =
let len = number.Length
let rec parse (index: int) (nSign: double) (signMultiplier: double) (nAccumulator: int64) : float =
if index < len then
match number.[index] with
| x when x >= '0' && x <= '9' -> parse (index + 1) (signMultiplier * nSign) signMultiplier (nAccumulator * 10L + int64 x - int64 '0')
| x when x = '.' -> parse (index + 1) nSign 0.1 nAccumulator
| x when x = '-' -> parse (index + 1) -nSign signMultiplier nAccumulator
| _ -> parse (index + 1) nSign signMultiplier nAccumulator
else
double nAccumulator * nSign
parse 0 +1. 1. 0L
let benchmark name (func: string -> double) =
let allowedError = 0.00001
printf "checking %s - " name
let sw = Stopwatch()
sw.Start()
numbers
|> List.iter (fun (num, str) ->
let parsed = func str
let delta = num - parsed
if abs delta > allowedError then
failwithf "(%f, %s) not matching %f" num str parsed
)
sw.Stop()
printfn "%i ms" sw.ElapsedMilliseconds
benchmark ".net parser" (fun x -> double x)
benchmark "parser1" (fun x -> parseString x)
0
Is there anything obvious I missed to speed this up?
Additionally, there is something I do not understand: I tried to make the test numbers an array instead of a list and suddenly the processing took longer, while I'd expect the opposite. If anyone has some insights as to why it is happening, I'd be happy to know. You can just change the toList to toArray and replace the List with Array in the benchmark loop to test this.
Edit:
to load the data, here is the code I use:
// load a csv file
let loadCSV (stream: Stream) =
seq {
use s = new StreamReader (stream)
while not s.EndOfStream do
yield s.ReadLine ()
}
|> Seq.map (fun line -> line.Split(",") |> Array.toList)
|> Seq.toList
I would like to convert a list of zeros and ones to a char.
example :
bitToChar([1,0,0,0,1,0,1]) = $Q
Thanks.
Another way to do it is to use a bit string comprehension:
X = [1,0,0,0,1,0,1],
<<C:7>> = << <<Bit:1>> || Bit <- lists:reverse(X) >>,
$Q == C.
That is, pick one element at a time from the list, and use each element as a bit in the binary being built, and finally extract a seven-bit number into the variable C.
You can add $0 to each of them (to make it a string with $0s and $1s), reverse the list, and use list_to_integer/2 with base 2:
1> list_to_integer(lists:reverse([N + $0 || N <- [1,0,0,0,1,0,1]]), 2) == $Q.
true
You can also use lists:foldl. The code is slightly longer but it doesn't use list_to_binary:
1> element(2, lists:foldl(fun(Digit, {Mul, Acc}) -> {Mul * 2, Acc + Digit * Mul} end, {1, 0}, Xs)) == $Q. true
This is basically equivalent to doing: 1 * 1 + 0 * 2 + 0 * 4 + 0 * 8 + 1 * 16 + 0 * 32 + 1 * 64.
$Q = lists:foldr(fun(X,Acc) -> X + (Acc bsl 1) end, 0,[1,0,0,0,1,0,1]).
Since $Q is integer value all you have to do is use in BitToChar conversion from binary based number to decimal based number.
Simplest conversion is:
to_decimal(X) ->
to_decimal(lists:reverse(X), 1, 0).
% you can validate that if H = 1 then add, if other not but I omitted this validation
to_decimal([H | T], Times, Acc) ->
to_decimal(T, 2 * Times, H * Times + Acc);
to_decimal([], _Times, Acc) -> Acc.
And then it will return integer.
In your case:
> $Q = 81.
81
> $Q == 81.
true
I'm writting some generators and an Arbitrary, but is too slow (see the GC numbers also). I think I have an error on my code, but I can't figure out where. Or my approach (map2 (fold)) is "weird"?.
Generators:
type Generators () =
static let notAllowed = Array.append [| '0'..'9' |] [| '\n'; '\r'; '['; ']'; '/'; |]
static let containsInvalidValues (s : string) = s.IndexOfAny(notAllowed) <> -1
static member positiveIntsGen() = Arb.generate<PositiveInt> |> Gen.map int
static member separatorStringGen() =
Arb.generate<NonEmptyString>
|> Gen.suchThat (fun s -> s.Get.Length < 5 && not (s.Get |> containsInvalidValues))
Arbitrary:
let manyNumbersNewLineCustomDelimiterStrInput =
Gen.map2 (fun (ints : int[]) (nes : NonEmptyString) ->
Array.fold (fun acc num ->
if num % 2 = 0 then acc + "," + num.ToString()
else if num % 3 = 0 then acc + "\n" + num.ToString()
else acc + "\n" + num.ToString()) ("//[" + nes.Get + "]\n") ints )
(Generators.array12OfIntsGen())
(Generators.separatorStringGen())
|> Arb.fromGen
The configuration have the MaxTest = 500 and it takes ~5 minutes to complete.
Output (using #timer):
StrCalcTest.get_When pass an string that starts with "//[" and contains "]\n" use the multicharacter value between them as separator-Ok, passed 500 tests.
Real: 00:07:03.467, CPU: 00:07:03.296, GC gen0: 75844, gen1: 71968, gen2: 4
Without actually testing anything, my guess would be that the problematic part is this:
Arb.generate<NonEmptyString>
|> Gen.suchThat (fun s -> s.Get.Length < 5 && not (s.Get |> containsInvalidValues))
This means that you will generate strings and filtering out all those that satisfy certain conditions. But if the conditions are too restrictive, FsCheck might need to generate a very large number of strings until you actually get some that pass the test.
If you can express the rule so that you are generating the strings so that everything you generate is a valid string, then I think it should be faster.
Could you, for example, generate a number n (for the string length) followed by n values of type char (that satisfy your conditions) and then append them to form the separator string? (I think FsCheck's gen { .. } computation might be a nice way of writing that.)
If a number is exprimed on 4 bytes, from LSB to MSB, how to convert it in integer ?
example:
<<77,0,0,0>> shall give 77
but
<<0,1,0,0>> shall give 256
Let S = <<0,1,0,0>>,
<<L1,L2,L3,L4>> = S,
L = L1*1 + L2*256 + L3*65536 + L4*16777216,
But it's not elegant ...
The bit syntax in Erlang does this in a very straightforward way:
<<A:32/little>> = <<0,1,0,0>>,
A.
% A = 256
or as a function:
decode(<<Int:32/little>>) -> Int.
% decode(<<0,1,0,0>>) =:= 256.
EDIT (this is the correct answer, and sorry for discovering it late...)
> binary:decode_unsigned(<<0,1,0,0>>,little).
256
The easier way would be something like:
decode_my_binary( <<A,B,C,D>> ) ->
A + B*256 + C*65536 + D*16777216.
EDIT:
As per your edit, if you find this one not very elegant, you can try other approaches. Still I think the above is the correct way of doing it. You can write a recursive function (not tested, but you get the idea):
decode( B ) -> decode(binary_to_list(B), 0, 1).
decode( [], R, _ ) -> R;
decode( [H|T], R, F) ->
decode(T, R + H*F, F*256).
but this is clearly slower. Another possibility is to have the list of the binary digits and the list of multipliers and then fold it:
lists:sum(lists:zipwith( fun(X,Y) -> X*Y end,
binary_to_list(B), [ math:pow(256,X) || X <- [0,1,2,3] ])).
Or if you want a variable number of digits:
fun(Digits) ->
lists:sum(lists:zipwith( fun(X,Y) -> X*Y end,
binary_to_list(B), [ math:pow(256,X) || X <- lists:seq(0,Digits-1])).
where Digits tell you the digit number.