Convert uint24 to HEX string in Solidity - bit-manipulation
I am trying to convert uint24 value of a kind 0x00ff08 to a human readable string with the same characters in Solidity smart contract which I am going to deploy on RSK. In my question about bytes3 to hex string casting I was advised for these purposes to use a function
function uint24tohexstr(uint24 i) public pure returns (string memory) {
bytes memory o = new bytes(6);
uint24 mask = 0x00000f;
o[5] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[4] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[3] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[2] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[1] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[0] = bytes1(uint8tohexchar(uint8(i & mask)));
return string(o);
}
I wanted to make use of a loop in that function and rewrote it like this
function uint24ToHexStr(uint24 i) public pure returns (string memory) {
bytes memory o = new bytes(6);
uint24 mask = 0x00000f; // hex 15
for(uint k = 5; k >= 0; k -= 1) {
o[k] = bytes1(uint8ToHexCharCode(uint8(i & mask)));
i >>= 4;
}
return string(o);
}
But unfortunately this function causes runtime error because on the last iteration unsigned integer k becomes -1. The first thing that crossed my mind was to increase k by one so that
for(uint k = 6; k >= 1; k -= 1) {
o[k - 1] = bytes1(uint8ToHexCharCode(uint8(i & mask)));
}
Can anyone think of a more elegant way to achieve the same result?
This line:
for(uint k = 5; k >= 0; k -= 1) {
If k is of type uint, when will k >= 0 ever evaluate to false? (hint: never)
Change k from type uint to int and problem is solved.
for(int k = 5; k >= 0; k -= 1) {
o[k] = bytes1(uint8ToHexCharCode(uint8(i & mask)));
i >>= 4;
}
Or
for(uint k = 0; k< 6; k += 1) {
o[5-k] = bytes1(uint8ToHexCharCode(uint8(i & mask)));
i >>= 4;
}
I like the 2nd option in #selbie's answer; and thought what if we used a different type of loop control structure. A regular while loop would inherit the same "final iteration uint underflow" problem that the for loop has. Switching to a do .. while loop, on the other hand, allows you to shift the evaluation of the condition from being checked before the iteration, to being checked after the iteration. This can be applied to your implementation like so:
function uint24ToHexStr(uint24 i) public pure returns (string memory) {
bytes memory o = new bytes(6);
uint24 mask = 0x00000f; // hex 15
uint k = 6;
do {
k--;
o[k] = bytes1(uint8ToHexCharCode(uint8(i & mask)));
i >>= 4;
} while (k > 0);
return string(o);
}
This avoids both the uint underflow, and also does not require k - 1 for array indices within the loop. In terms of gas cost, I would "guesstimate" that it would be close to the original implementation of the same function from the previous question. (but actually try both out and compare to confirm)
Alternative answer, also taking some inspiration from #selbie's answer of forward iteration, but instead of reversing the index order,
get the target half-byte by switching from a bitwise-and mask
to a bit-shift of 5 half-bytes (20 bits).
Like so:
function uint24ToHexStrAlt2(uint24 i) public pure returns (string memory) {
bytes memory o = new bytes(6);
uint k = 0;
do {
o[k] = bytes1(uint8ToHexCharCode(uint8(i >> 20))); // shift by 5 nibbles instead of mask
i <<= 4;
k +=1;
} while (k < 6);
return string(o);
}
Related
Multiply Bits with factor (GLSL)
I want to have a method which multiplies each bit in a number with a factor. For example if factor is 3, each bit in the number is used three times before the next bit in the number is used. I'm working with GLSL.
Did it with C# private int DuplicateBitsByFactor(int value, int factor) { var size = sizeof(ushort) * 8; var binaryString = new StringBuilder(); for (var i = size; i >= 0; i--) for (var j = 0; j < factor; j++) binaryString.Append(GetBitOnLocation(value, i)); var duplicateBitsByFactor = Convert.ToInt32(binaryString.ToString(), 2); return duplicateBitsByFactor; } private int GetBitOnLocation(int value, int location) { return (value & (1 << location)) == 0 ? 0 : 1; } Any optimization?
From mathematic function to c++ code
I am trying to implement this F(S) function: bellow is my code but is not working: double EnergyFunction::evaluate(vector<short> field) { double e = 0.0; for (int k = 1; k < field.size() - 1; k++){ double c = 0.0; for (int i = 1; i < field.size() - k; i++) { c += field[i] * field[i + k]; } e += pow(c, 2); } double f = pow(field.size(), 2) / ( 2 * e ); return f; } For example F(S) function should return value 8644 for vector: 1,1,1,-1,-1,-1,1,-1,1,1,-1,1,-1,1,-1,1,-1,-1,1,1,1,1,-1,-1,-1,1,1,1,1,-1,1,-1,1,1,-1,-1,1,1,1,1,-1,-1,-1,1,-1,-1,1,-1,-1,1,1,-1,1,-1,-1,1,1,-1,1,-1,1,-1,1,-1,1,-1,1,1,-1,-1,-1,-1,-1,-1,1,-1,1,1,1,-1,1,1,-1,1,1,-1,1,-1,1,1,1,-1,-1,1,1,-1,-1,1,1,1,1,1,1,1,1,-1,1,-1,1,-1,1,-1,-1,1,-1,-1,1,-1,-1,1,-1,-1,-1,-1,-1,1,1,1,1,1,-1,-1,-1,1,-1,-1,1,-1,-1,1,-1,-1,1,-1,1,-1,-1,1,1,1,1,1,1,-1,1,-1,1,-1,1,1,1,1,1,1,-1,1,-1,-1,-1,1,-1,1,1,-1,-1,-1,-1,1,-1,-1,-1,1,1,-1,-1,1,1,1,-1,-1,1,1,1,1,-1,1,1,-1,1,-1,-1,1,-1,-1,-1,-1,1,-1,-1,-1,1,-1,-1,1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,1,1,-1,1,1,-1,-1,-1,1,-1,-1,1,-1,-1,-1,1,1,1,-1,-1,-1,-1,1,1,1,-1,1,-1,-1,1,-1,1,1,-1,-1,-1,-1,1,-1,1,1,1,1,1,1,-1,1,1,1,-1,-1,-1,-1,1,-1,1,1,1,1,-1,1,1,1,1,1,-1,-1,-1,1,-1,-1,1,1,1,-1,1,1,1,-1,1,1 I need another par of eyes to look at my code because I am a bit lost here. :)
after refactoring: double EnergyFunction::evaluate(vector<short> field) { double e = 0.0; int l = field.size() for (int k = 1; k < l; k++){ double c = 0.0; for (int i = 0, j = k; j < l; i++, j++) { c += field[i] * field[j]; } e += c*c; } return l*l / ( e+e ); } explanation: 1. we need to iterate (L-1) times 2. we need to shift the base and offset indexes until we reach the last one 3. c*c and e+e are quicker and easier to read
You are mapping variables into different ranges using the same names, which is always going to be confusing. Better is to keep ranges and names the same as in the math, and only subtract one for 0-base indexes at indexing time. Also might as well use L explicitly: int L = field.size(); for (int k = 1; k <= L-1; k++){ ... for (int i = 1; i <= L-k; i++) { c += field[i -1] * field[i+k -1]; ...
Segments sum algorithm
I am trying to solve the following task: 1) Given the array A of size N. 2) Given set of range update queries i.e. (L, R, val) that should do A[i] += val for L <= i <= R. 3) Given the set of range sum queries i.e. (L, R) that should return sum(A[i]) for L <= i <= R. Constraints: 1) Size of A, segments and queries sets N, N1, N2 <= 2^24. 2) 0 <= L <= 2^24, 0 <= R <= 2^24, 0 <= val <= 2^24. Problem is to calculate sum of all range sum queries (S) modulo 2^32. It seems that one may implement Segment tree to get desired sum with O(NlogN) time but actually we don't need to use this data structure. Instead, we can somehow calculate S in O(N) time just using 2 or 3 arrays. What is the general idea here? I has recently wrote some algorithm in C++ to this problem but that is not optimal. Pseudocode: Create two arrays Add[0..N-1] and Substract[0..N-1]. Iterate over the set of range updates and do Add[L] += val and Substract[R] += val. Create array Partial_sum[0..N] Partial_sum[0] = 0, what_to_add = 0. For i in [1..N]: 5.1. Partial_sum[i] = Partial_sum[i - 1] + Add[i - 1] + what_do_add 5.2. what_do_add = what_to_add + Add[i - 1] - Substract[i - 1] We get Partial_sum array and can easily calculate any segment sum (L, R) in O(1) time just like Partial_sum[R+1] - Partial_sum[L]. But, the problem is that step 2 is too slow. Also, the loop in step 5 is hard to undestand. That is O(n) solution but constant is too high. I know there should be the way to improve step 5 but I don't undestand how to do this. Could someone give some ideas or even suggest their own algorithm to solve this problem? Thank you. My algorithm implementation: #include <cstring> #include <iostream> #include <stdio.h> typedef unsigned int UINT; typedef unsigned long long ULL; //MOD and size of A const ULL MOD = 4294967296LL; // 2^32 const size_t N = 16777216; // 2^24 //params for next_rand() UINT seed = 0; UINT a; UINT b; //get random segment UINT next_rand() { seed = seed * a + b; return seed >> 8; } int main() { UINT N1, N2; std::cin >> N1 >> N2; std::cin >> a >> b; UINT* add = new UINT[N]; //Add array UINT* subs = new UINT[N]; //Substraction array UINT* part_sum = new UINT[N + 1]; //Partial sums array memset(add, 0, sizeof(UINT) * N); memset(subs, 0, sizeof(UINT) * N); memset(part_sum, 0, sizeof(UINT) * (N + 1)); //Initialize arrays //step 2 for (size_t i = 0; i < N1; ++i) { UINT val = next_rand(); UINT l = next_rand(); UINT r = next_rand(); if (l > r) { std::swap(l, r); } add[l] = (add[l] + val); subs[r] = (subs[r] + val); } part_sum[0] = 0; UINT curr_add = 0; //step 5 for (size_t i = 1; i <= N; ++i) { part_sum[i] = (part_sum[i - 1] + curr_add + add[i - 1]); curr_add = (curr_add + add[i - 1] - subs[i - 1]); } UINT res_sum = 0; //Get any segment sum in O(1) for (size_t i = 0; i < N2; ++i) { UINT l = next_rand(); UINT r = next_rand(); if (l > r) { std::swap(l, r); } res_sum = (res_sum + part_sum[r + 1] - part_sum[l]); } std::cout << res_sum; delete []add; delete []subs; delete []part_sum; return 0; }
I've implemented described algorithm in different way. It should work faster. It should work faster than before at maximum values of update and sum query sizes. #include <iostream> #include <stdio.h> #include <vector> typedef unsigned int UINT; typedef unsigned long long ULL; const ULL MOD = 4294967296LL; // 2^32 const size_t N = 16777216; // 2^24 UINT seed = 0; UINT a; UINT b; UINT next_rand() { seed = seed * a + b; return seed >> 8; } std::vector <std::pair<UINT, UINT> > add; int main() { UINT upd_query_count; UINT sum_query_count; // freopen("fastadd.in", "r", stdin); // freopen("fastadd.out", "w", stdout); scanf("%u", &upd_query_count); scanf("%u", &sum_query_count); scanf("%u", &a); scanf("%u", &b); add.reserve(N+1); for (size_t i = 0; i < upd_query_count; ++i) { UINT val = next_rand(); UINT l = next_rand(); UINT r = next_rand(); if (l > r) { add[r].first += val; add[l + 1].first -= val; } else { add[l].first += val; add[r + 1].first -= val; } } for (size_t i = 0; i < sum_query_count; ++i) { UINT l = next_rand(); UINT r = next_rand(); if (l > r) { ++add[r].second; --add[l + 1].second; } else { ++add[l].second; --add[r + 1].second; } } UINT curr_add = 0; UINT res_sum = 0; UINT times = 0; for (size_t i = 0; i < N; ++i ) { curr_add += add[i].first; times += add[i].second; res_sum += curr_add * times; } printf("%u\n", res_sum); return 0; }
So add ad subs are very large arrays. The first place you should look for a speed up here is in memory access. As N1 becomes large you will end up with a tremendous number of cache misses. This is probably somewhat beyond the scope to explain so I'll link: http://en.wikipedia.org/wiki/CPU_cache As far as a way you can speed this up. Lets try to improve spatial equality by ordering our access. std::vector<std::pair<UINT, UINT>> l{N1}; std::vector<std::pair<UINT, UINT>> r{N1}; for(size_t i = 0; i < N1; ++i){ const UINT val = next_rand(); const UINT first = next_rand(); const UINT second = next_rand(); if(first > second){ l[i] = std::make_pair(second, val); r[i] = std::make_pair(first, val); }else{ l[i] = std::make_pair(first, val); r[i] = std::make_pair(second, val); } } std::sort(l.begin(), l.end()); std::sort(r.begin(), r.end()); for(size_t i = 0; i < N1; ++i){ add[l[i].first] += l[i].second; subs[r[i].first] += r[i].second; } Keep a couple things in mind, std::pair's operator< compares the first element and if those are equal compares the second. That's how I'm able to use std::sort without writing any more code. However if first is equal for two elemnts, the highest val will always be the second one added. It doesn't seem like that would be a problem in your current code, but if it becomes one you can solve it by writing your own sort loop, rather than relying on std::sort. Also depending on how sparse access is to each cache block it may be faster to do your additions in separate loops. As always the only way you can really improve performance is when working with actual numbers so be sure to do your own bench marking as your're comparing methods.
extracting binary data out of 8-bit byte and converting it to primitive types [C++]
I have a vector of integers vector<int> that has 48 items in it. I want to extract binary data out of this(not sure if this is correct way to call it please edit it if it's wrong) i.e. a sequence of one or more bits and then convert them to a primitive type like int. I have come up with this solution: int extractValue(vector<int> v, int startBit, int endBit) { int beginByteIndex = (startBit / 8); int endByteIndex = (endBit / 8); vector<bool> bits; bits.clear(); int startIndex = startBit % 8; int endIndex = endBit % 8; int value = v[beginByteIndex]; value = (value << startIndex); int temp = 8; if (beginByteIndex == endByteIndex) { temp = endIndex + 1; } for (int i = startIndex; i < temp; i++) { int temp = 0x80 & value; bits.push_back(temp); value <<= 1; } for (int i = beginByteIndex + 1; i < endByteIndex; i++) { value = v[i]; for (int j = 0; j < 8; j++) { int temp = 0x80 & value; bits.push_back(temp); value <<= 1; } } if (endByteIndex > beginByteIndex) { value = v[endByteIndex]; for (int i = 0; i <= endIndex; i++) { int temp = 0x80 & value; bits.push_back(temp); value <<= 1; } } int size = bits.size(); int p = 1; int result = 0; for (int i = size - 1; i >= 0; i--) { result += (bits[i] * p); p *= 2; } return result; } but this function is long, difficult to read and is done in C style. could someone please suggest a C++ way of doing this. I'm almost certain that C++ has a good, short and elegant way of doing this. also please edit the question so others with similar problem can benefit from it. Unfortunately My English is not that good to express it in a more general way. EDIT: as requested in comments for example I want to extract following information with following positions and length: int year = extractValue(data, 0, 6); int month = extractValue(data, 7, 10); int day = extractValue(data, 11, 15);
a simple solution: convert each byte to hex string (ostringstream or even sprintf can help), you got 2 digits, range is 0 to F. for each hex digit you can create the bitmap like this: 0 = 0000, 1 = 0001, 2 = 0010, ..., F = 1111, add bits to the vector according to the bitmap to recover - you take 4 bits and translate it back to digit, then take 2 digits and convert back to byte (say by adding 0x to the hex, isringstream to byte).
Finding Pythagorean Triples: Euclid's Formula
I'm working on problem 9 in Project Euler: There exists exactly one Pythagorean triplet for which a + b + c = 1000. Find the product abc. The following code I wrote uses Euclid's formula for generating primes. For some reason my code returns "0" as an answer; even though the variable values are correct for the first few loops. Since the problem is pretty easy, some parts of the code aren't perfectly optimized; I don't think that should matter. The code is as follows: #include <iostream> using namespace std; int main() { int placeholder; //for cin at the end so console stays open int a, b, c, m, n, k; a = 0; b = 0; c = 0; m = 0; n = 0; k = 0; //to prevent initialization warnings int sum = 0; int product = 0; /*We will use Euclid's (or Euler's?) formula for generating primitive *Pythagorean triples (a^2 + b^2 = c^2): For any "m" and "n", *a = m^2 - n^2 ; b = 2mn ; c = m^2 + n^2 . We will then cycle through *values of a scalar/constant "k", to make sure we didn't miss anything. */ //these following loops will increment m, n, and k, //and see if a+b+c is 1000. If so, all loops will break. for (int iii = 1; m < 1000; iii++) { m = iii; for (int ii = 1; n < 1000; ii++) { n = ii; for (int i = 1; k <=1000; i++) { sum = 0; k = i; a = (m*m - n*n)*k; b = (2*m*n)*k; c = (m*m + n*n)*k; if (sum == 1000) break; } if (sum == 1000) break; } if (sum == 1000) break; } product = a * b * c; cout << "The product abc of the Pythagorean triplet for which a+b+c = 1000 is:\n"; cout << product << endl; cin >> placeholder; return 0; } And also, is there a better way to break out of multiple loops without using "break", or is "break" optimal? Here's the updated code, with only the changes: for (m = 2; m < 1000; m++) { for (int n = 2; n < 1000; n++) { for (k = 2; (k < 1000) && (m > n); k++) { sum = 0; a = (m*m - n*n)*k; b = (2*m*n)*k; c = (m*m + n*n)*k; sum = a + b + c; if ((sum == 1000) && (!(k==0))) break; } It still doesn't work though (now gives "1621787660" as an answer). I know, a lot of parentheses.
The new problem is that the solution occurs for k = 1, so starting your k at 2 misses the answer outright. Instead of looping through different k values, you can just check for when the current sum divides 1000 evenly. Here's what I mean (using the discussed goto statement): for (n = 2; n < 1000; n++) { for (m = n + 1; m < 1000; m++) { sum = 0; a = (m*m - n*n); b = (2*m*n); c = (m*m + n*n); sum = a + b + c; if(1000 % sum == 0) { int k = 1000 / sum; a *= k; b *= k; c *= k; goto done; } } } done: product = a * b * c; I also switched around the two for loops so that you can just initialize m as being larger than n instead of checking every iteration. Note that with this new method, the solution doesn't occur for k = 1 (just a difference in how the loops are run, this isn't a problem)
Presumably sum is supposed to be a + b + c. However, nowhere in your code do you actually do this, which is presumably your problem. To answer the final question: Yes, you can use a goto. Breaking out of multiple nested loops is one of the rare occasions when it isn't considered harmful.