I was trying to run a Hilbert curve code written in C, which I found here
http://www.tddft.org/svn/octopus/trunk/src/grid/hilbert.c
The code runs, but the results I get form the output are not correct. I made a simple driver routine, that takes 3 values as arguments from the command line and passes them to a Hilbert curve encode, decode routines.
More precisely, I can't decode back the original coordinates (x,y,z).
One of my problems was to understand what the variable nbits is doing. I assume it is the size of the encoded Hilbert value. To check this I tried to modify the original definition of one of the functions from
void InttoTranspose(const int dim, const long long int h, int * x)
to
void InttoTranspose(const int dim, const long long int h, int * x, int* size)
Where I assign to *size the bit count variable ifbit. Anyway, this all didn't work. Therefore I would like to ask for your help.
The modified code is here:
#include<stdio.h>
//#include <config.h>
#include <assert.h>
/* This code is based on the implementation of the Hilbert curves
presented in:
J. Skilling, Programming the Hilbert curve, AIP Conf. Proc. 707, 381 (2004); http://dx.doi.org/10.1063/1.1751381
*/
*/ The int* size was included later in an attempt to find the proper size /*
/* void InttoTranspose(const int dim, const long long int h, int * x)*/
void InttoTranspose(const int dim, const long long int h, int * x, int* size){
/* the code uses some funny way of storing the bits */
int idir, ibit, ifbit;
for(idir = 0; idir < dim; idir++) x[idir] = 0;
ifbit = 0;
for(ibit = 0; ibit < 21; ibit++){
for(idir = dim - 1; idir >= 0; idir--){
x[idir] += (((h>>ifbit)&1)<<ibit);
ifbit++;
}
}
*size=ifbit; // I think that this should be nbits
}
void TransposetoAxes(int* X, int b, int n ){ /* position, #bits, dimension */
int N = 2 << (b-1), P, Q, t;
int i;
/* Gray decode by H ^ (H/2) */
t = X[n-1] >> 1;
for(i = n - 1; i > 0; i--) X[i] ^= X[i-1];
X[0] ^= t;
/* Undo excess work */
for( Q = 2; Q != N; Q <<= 1 ) {
P = Q - 1;
for( i = n-1; i >= 0 ; i-- ){
if( X[i] & Q ) {
X[0] ^= P; /* invert */
} else{
t = (X[0]^X[i]) & P; X[0] ^= t; X[i] ^= t; /* exchange */
}
}
}
}
//void FC_FUNC_(hilbert_index_to_point, HILBERT_INDEX_TO_POINT)(const int * dim, const int * nbits, const long long int * index, int * point){
// InttoTranspose(*dim, *index, point);
// TransposetoAxes(point, *nbits, *dim);
//}
int main(int argc,char* argv[]){
long long int hilbert;
int i=0,x[2],m;
while(argc--){
if(m=atoi(*argv++)) x[i++]=m, printf("--> %5d %5d\n",m,argc);
}
printf("x= %5d y= %5d z= %5d \n",x[0],x[1],x[2]);
InttoTranspose(3, hilbert, x,&m);
printf("hilbert encoded --> %llu size -->%d \n",hilbert,m);
TransposetoAxes(x,m, 3 );
printf("x= %5d y= %5d z= %5d \n",x[0],x[1],x[2]);
return 0;
}
Related
So, I had been trying to write the code for the Small Triangles, Large Triangles problem of C in Hackerrank. Before, I state what problem I'm facing, I'll attach the question-
I only wrote the sort_by_area, swap and area functions here. The rest of it was given and unchangeable. The code I've written is getting executed properly but the structures aren't getting sorted correctly. Here is the expected output & my output-
I just cannot figure out why it is getting such weirdly swapped. If anyone could help, would mean a lot.
My code is-
#include <stdlib.h>
#include <math.h>
struct triangle
{
int a;
int b;
int c;
};
typedef struct triangle triangle;
void sort_by_area(triangle* tr, int n) {
int i, j, swapped;
for (i = 0; i < n-1; i++)
{
swapped = 0;
for (j = 0; j < n-i-1; j++)
{
if (area(tr[j].a, tr[j].b, tr[j].c) > area(tr[j+1].a, tr[j+1].b, tr[j+1].c))
{
swap(&tr[j], &tr[j+1]);
swapped = 1;
}
}
if (swapped == 0)
break;
}
}
void swap(struct triangle **xp, struct triangle **yp)
{
struct triangle *temp = *xp;
*xp = *yp;
*yp = temp;
}
int area(int a, int b, int c){
int p=(a+b+c)/2;
int q=p*(p-a)*(p-b)*(p-c);
return sqrt(q);
}
int main()
{
int n;
scanf("%d", &n);
triangle *tr = malloc(n * sizeof(triangle));
for (int i = 0; i < n; i++) {
scanf("%d%d%d", &tr[i].a, &tr[i].b, &tr[i].c);
}
sort_by_area(tr, n);
for (int i = 0; i < n; i++) {
printf("%d %d %d\n", tr[i].a, tr[i].b, tr[i].c);
}
return 0;
}```
Enable all warnings
This quickly led to swap() swapping pointers and not data.
// Corrected - swap data
void swap(struct triangle *xp, struct triangle *yp) {
struct triangle temp = *xp;
*xp = *yp;
*yp = temp;
}
Function order
Move area(), swap() definitions before calling them.
Area
(int) sqrt(q) may return the same value for different qs.
Example: (int) sqrt(100), (int) sqrt(110), (int) sqrt(120)
All return 10. Sorting will not certainly sort according to area.
Simple return the square of the area. Mathematically, sorting by area squared same as area.
int area_squared(int a, int b, int c){
int p=(a+b+c)/2;
int q=p*(p-a)*(p-b)*(p-c);
// return sqrt(q);
return q;
}
Although one could code using double, let us stay with integers.
Watch out for a+b+c as odd as odd/2 forms a truncated quotient.
Perhaps return the square of the area, scaled each side by 2?
int area_squared2(int a, int b, int c){
a *= 2; b *= 2; c *= 2;
// a+b+c is certianly even
int p=(a+b+c)/2;
int q=p*(p-a)*(p-b)*(p-c);
return q;
}
A remaining concern is int overflow. Consider long long math.
long long area_squared2LL(int a, int b, int c){
long long aa = a * 2LL;
long long bb = b * 2LL;
long long cc = c * 2LL;
long long pp = (aa+bb+cc)/2;
long long qq = pp*(pp-aa)*(pp-bb)*(pp-cc);
return qq;
}
Tip: Allocate by referenced data, not type
Easier to code right, review and maintain.
// triangle *tr = malloc(n * sizeof(triangle));
triangle *tr = malloc(sizeof *tr * n);
if (tr == NULL) {
// use tr
...
free(tr);
tr = NULL;
}
I programed a function to generate pseudo-random numbers, but my compiler doesn't vectorize this not vectorized: complicated access pattern.
How can I achive that the compiler vectorize this?
I use the comand gcc -O3 -ffast-math -funroll-all-loops -ftree-vectorize -fopt-info-vec-missed -lm -g $1 -o ${2}.O3
unsigned int seed;
unsigned int temp;
#define val13 13
unsigned int var1 = 214013;
unsigned int var2 = 2531011;
inline int myRandom() {
seed = (var1*seed + var2);
return (seed>>val13);
}
If I change the code to this I manage to vectorize but I do not get the expected result.
inline int myRandom() {
return ((var1*seed + var2)>>val13);
}
How can I achive the compiler to vectorize this function and get the expected result?
The generator function f on the seed is a linear congruential generator that is easily composed with itself to implement f2, f3, f4, and so on. Then a vectorized generator can be implemented that prepares an initial vector block from one seed and then uses fB to calculate results in B lanes each independent of each other. Here is a proof of concept. Various embellishments are possible, such as keeping a vector of seeds instead of a single seed and modifying FillRandomVector to handle arbitrary N.
#include <stdio.h>
#include <stdlib.h>
#define Block 4 // Number of lanes (elements) in a vector block.
static const unsigned int var1 = 214013;
static const unsigned int var2 = 2531011;
// Original generator function, modified to take a pointer to the seed.
static inline int MyRandom(unsigned int *seed)
{
*seed = var1 * *seed + var2;
return *seed >> 13;
}
// New parameters for a vectorized generator.
static unsigned int var1Vector;
static unsigned int var2Vector;
/* Initialize parameters for vectorized generator by computing them from the
scalar parameters.
*/
static void Initialize(void)
{
var1Vector = 1;
var2Vector = 0;
for (int i = 0; i < Block; ++i)
{
var1Vector *= var1;
var2Vector = var2Vector * var1 + var2;
}
}
// Fill array with generated numbers using scalar method.
static void FillRandomScalar(unsigned int *seed, size_t N, int *Destination)
{
for (size_t n = 0; n < N; ++n)
Destination[n] = MyRandom(seed);
}
/* Fill array with generated numbers using vectorizable method.
For proof of concept only, so handles only certain N:
N must be a positive multiple of Block.
*/
static void FillRandomVector(unsigned int *seed, size_t N, int *Destination)
{
// Prepare a vector of seeds and generate the first block of results.
unsigned seedVector[Block];
unsigned int S = *seed;
for (size_t n = 0; n < Block; ++n)
{
S = S * var1 + var2;
seedVector[n] = S;
Destination[n] = S >> 13;
}
// Generate the remaining results using independent lanes.
for (size_t n = Block; n < N; n += Block)
for (size_t lane = 0; lane < Block; ++lane)
{
seedVector[lane] = seedVector[lane] * var1Vector + var2Vector;
Destination[n + lane] = seedVector[lane] >> 13;
}
*seed = seedVector[Block-1];
}
#define N 100
int main(void)
{
Initialize();
int expected0[N], observed0[N];
int expected1[N], observed1[N];
unsigned int seed;
seed = 17;
FillRandomScalar(&seed, N, expected0);
FillRandomScalar(&seed, N, expected1);
seed = 17;
FillRandomVector(&seed, N, observed0);
FillRandomVector(&seed, N, observed1);
for (size_t n = 0; n < N; ++n)
{
if (observed0[n] != expected0[n])
{
printf("observed0[%zu] = %d, but expected0 %d.\n",
n, observed0[n], expected0[n]);
exit(EXIT_FAILURE);
}
}
for (size_t n = 0; n < N; ++n)
{
if (observed1[n] != expected1[n])
{
printf("observed1[%zu] = %d, but expected1 %d.\n",
n, observed1[n], expected1[n]);
exit(EXIT_FAILURE);
}
}
}
I have this one task. To make it more clear, I am gonna use picture below as an example. Input and output is separated with dotted line. First line of input is number N - number of sets. For every set, it's first line are 2 numbers - first one declares how many numbers am I gonna process and second one is number of intervals. Second line specifies the numbers to process and third line contains 2 numbers X and Y, which create and interval. For every interval I have to output 3 numbers - lowest number on interval, index of highest number on interval and XOR of all numbers. Everything is running fine except it is really slow for big data and I have no idea how to make work faster. I have attached my code and large data input as well.
input.txt
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int id;
int index;
} Censor;
int Xor(const int x, const int y, const Censor array[]) {
int xor = array[x].id;
if (x == y) {
return xor;
}
for (int i = x + 1; i <= y; i++) {
xor ^= array[i].id;
}
return xor;
}
int int_cmp(const void *a, const void *b) {
const Censor *ia = (const Censor *)a;
const Censor *ib = (const Censor *)b;
return (ia->id - ib->id);
}
int LowestId(const int x, const int y, Censor array[]) {
int id = array[x].id;
if (x == y) {
return id;
}
qsort(array, y - x + 1, sizeof(Censor), int_cmp);
return array[0].id;
}
int HighestIdIndex(const int x, const int y, Censor array[]) {
int index = array[x].index;
if (x == y) {
return index;
}
qsort(array, y - x + 1, sizeof(Censor), int_cmp);
return array[y].index;
}
int main() {
int t, n, q, b, e;
int max = 100;
int count = 0;
int *output = (int *)malloc(max * sizeof(output));
scanf("%d", &t); //number of sets
for (int i = 0; i < t; i++) {
scanf("%d %d", &n, &q);
//I am making 3 separate arrays for numbers, because some of them are being sorted and some of them not
Censor lowest_id[n];
Censor highest_id_index[n];
Censor xor[n];
//This loop fills arrays with the numbers to be processed
for (int j = 0; j < n; j++) {
scanf("%d", &(lowest_id[j].id));
lowest_id[j].index = j;
highest_id_index[j].id = lowest_id[j].id;
highest_id_index[j].index = j;
xor[j].id = lowest_id[j].id;
xor[j].index = j;
}
// Now I am scanning intervals and creating output. Output is being stored in one dynamically allocated array.
for (int k = 0; k < q; k++) {
scanf("%d %d", &b, &e);
if (count + 3 >= max) {
max *=2;
int *tmp = (int *)realloc(output, max * sizeof(tmp));
if (tmp == NULL) {
return 1;
} else {
output = tmp;
}
}
output[count++] = LowestId(b, e, lowest_id);
output[count++] = HighestIdIndex(b, e, highest_id_index);
output[count++] = Xor(b, e, xor);
}
}
printf("---------------------\n");
for (int i = 0; i < count; i++) {
printf("%d\n", output[i]);
}
free(output);
return 0;
}
Thanks #Dan MaĊĦek and #Alex Lop. Sorting subarray in this case was unnecessary. Much easier is to iterate through the subarray in linear complexity.
I map spatial data onto a one dimensional interval. First I use a space filling Lebesgue curve (or Z curve) in order to connect my points. This works and I get the following plot if I use gnuplot:
Then I want to transform the Lebesgue curve to a Hilbert curve. But it does not work. This is the output:
So it seems to work at the beginning. But after a while strange things happen and I don't know why.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <limits.h>
#include <stdint.h>
#define DIM 2
// direction of hilbert curve
const unsigned char DirTable[4][4] =
{{1,2,0,0},{0,1,3,1},{2,0,2,3},{3,3,1,2}};
// Map z-order to hilbert curve
const unsigned char HilbertTable[4][4] =
{{0,3,1,2},{0,1,3,2},{2,3,1,0},{2,1,3,0}};
unsigned int Lebesgue2Hilbert(unsigned int lebesgue){
unsigned int hilbert = 1;
int level = 0;
int dir = 0;
for(unsigned int tmp=lebesgue; tmp>1; tmp>>=DIM, level++);
for(; level>0; level--){
int cell = (lebesgue >> ((level-1)*DIM)) & ((1<<DIM)-1);
hilbert = (hilbert<<DIM) + HilbertTable[dir][cell];
dir = DirTable[dir][cell];
}
return hilbert;
}
unsigned int Part1By1(unsigned int x)
{
x &= 0x0000ffff;
x = (x ^ (x << 8)) & 0x00ff00ff;
x = (x ^ (x << 4)) & 0x0f0f0f0f;
x = (x ^ (x << 2)) & 0x33333333;
x = (x ^ (x << 1)) & 0x55555555;
return x;
}
unsigned int EncodeMorton2(unsigned int x, unsigned int y)
{
return (Part1By1(y) << 1) + Part1By1(x);
}
struct sortKey{
int idx;
int key;
};
int compare (const void * a, const void * b)
{
return ( (*(struct sortKey*)b).key - (*(struct sortKey*)a).key );
}
int uniform_distribution(int rangeLow, int rangeHigh) {
double myRand = rand()/(1.0 + RAND_MAX);
int range = rangeHigh - rangeLow + 1;
int myRand_scaled = (myRand * range) + rangeLow;
return myRand_scaled;
}
int main (int argc, char **argv){
srand(time(NULL));
int n = 20;
int N = n*n;
// Uniform distribution
unsigned int pospar[DIM*N];
int k = 0;
for(unsigned int i=0; i<n; i++){
for(unsigned int j=0; j<n; j++){
pospar[DIM*k] = i;
pospar[DIM*k+1] = j;
k++;
}
}
// Lebesgue curve
unsigned int lkey[N];
for(int i=0; i<N; i++){
lkey[i] = EncodeMorton2(pospar[i*DIM+0],pospar[i*DIM+1]);
// printf("Lkey: %d\n", lkey[i]);
}
// Hilbert curve
unsigned int hkey[N];
for(int i=0; i<N; i++){
hkey[i] = Lebesgue2Hilbert(lkey[i]);
}
struct sortKey sk[N];
for(int i=0;i<N; i++){
sk[i].idx = i;
sk[i].key = hkey[i]; // "lkey[i]" or "hkey[i]"
}
qsort (sk, N, sizeof(struct sortKey), compare);
for (int i=0; i<N; i++){
printf ("%d %d\n", pospar[DIM*sk[i].idx], pospar[DIM*sk[i].idx+1]);
}
return 0;
}
Does anybody see what I have missed?
I have a function which calls another function and checks for condition to see if it's true, then it increments an integer. It's all fine and working but there will be a problem for very large results. It couldn't fit even in long long.
Example:
unsigned long long div(int num_first[], int num_second[])
{
unsigned long long div_result = 0;
while (compare(num_first, num_second) != -1)
{
divsub(num_first, num_second);
div_result++;
}
return div_result; // return div_result to main
}
That function works fine, but if div_result gets too large it crashes or causes undefined behavior. I want to store its result as array like so:
div_result = 25464878454
I want it to be:
div_result[max] = {2, 5, 4, 6, 4, 8, 7, 8, 4, 5, 4}
How do I achieve this?
EDIT:
I decided to use unsigned long long as folks suggest. That suits my case.
you can write your own little bigint plus increment functionality:
#include <iostream>
using namespace std;
const int MAXDIGITS=12;
void inc(int bignum[MAXDIGITS])
{
++bignum[MAXDIGITS-1];
int carry=0;
for(int i = MAXDIGITS-1; i>=0; --i)
{
bignum[i] += carry;
if(bignum[i]>9)
{
carry = 1;
bignum[i] = 0;
}
else
break;
}
}
int main()
{
int div_result[MAXDIGITS] = {0};
// test inc function
for(int i=0; i<9999991; ++i)
inc(div_result);
for(int i=0; i<MAXDIGITS; ++i)
cout << div_result[i];
return 0;
}
Well since I worked on your original question, I'll go ahead and post the results for that as well in case you change your mind. Converting a number to an array can be approached in a number of ways. Here is one scheme using a recursive function and a helper to correct the order of the digits.
note: for 32-bit OS, overflow will occurr due to x86 utilizing a 4-bit long, a 32-bit safe version using 8-bit long long is included below, a 3rd version using preprocessor directives integrating both versions is included at the end:
#include <stdio.h>
#include <stdlib.h>
#define MAXDIG 32
void digits2array (long x, long *a, size_t *idx);
int digits2array_rev (long x, long *a, size_t *i);
int main (void) {
long n = 25464878454;
long ar[MAXDIG] = {0};
size_t idx = 0;
int i = 0;
digits2array (n, ar, &idx); /* convert n to array */
printf ("\n array:\n\n");
for (i = 0; i < idx; i++) /* output results */
printf (" ar[%2d] : %ld\n", i, ar[i]);
return 0;
}
/* converts x to array of digits in a (reverse order) */
int digits2array_rev (long x, long *a, size_t *i)
{
if (x < 10) {
a[(*i)++] = x;
return x;
}
a[(*i)++] = x % 10;
return digits2array_rev (x / 10, a, i);
}
/* helper function to reverse results of digits2array_rev */
void digits2array (long x, long *a, size_t *idx)
{
long tmp[MAXDIG] = {0};
int i = 0;
digits2array_rev (x, tmp, idx); /* fill array with digits (reversed) */
for (i = 0; i < *idx; i++) /* reverse to correct order */
a[*idx - 1 - i] = tmp[i];
}
Output/Results
$ ./bin/digits2array
array:
ar[ 0] : 2
ar[ 1] : 5
ar[ 2] : 4
ar[ 3] : 6
ar[ 4] : 4
ar[ 5] : 8
ar[ 6] : 7
ar[ 7] : 8
ar[ 8] : 4
ar[ 9] : 5
ar[10] : 4
32-bit Safe Version (using long long)
On 32-bit OS's overflow would still occur. Changing the types to long long (8-bit int on x86), allows the program to operate on x86 without issue.
#include <stdio.h>
#include <stdlib.h>
#define MAXDIG 32
void digits2array (long long x, long long *a, size_t *idx);
long long digits2array_rev (long long x, long long *a, size_t *i);
int main (void) {
long long n = 25464878454;
long long ar[MAXDIG] = {0};
size_t idx = 0;
int i = 0;
digits2array (n, ar, &idx); /* convert n to array */
printf ("\n array:\n\n");
for (i = 0; i < idx; i++) /* output results */
printf (" ar[%2d] : %lld\n", i, ar[i]);
return 0;
}
/* converts x to array of digits in a (reverse order) */
long long digits2array_rev (long long x, long long *a, size_t *i)
{
if (x < 10) {
a[(*i)++] = x;
return x;
}
a[(*i)++] = x % 10;
return digits2array_rev (x / 10, a, i);
}
/* helper function to reverse results of digits2array_rev */
void digits2array (long long x, long long *a, size_t *idx)
{
long long tmp[MAXDIG] = {0};
int i = 0;
digits2array_rev (x, tmp, idx); /* fill array with digits (reversed) */
for (i = 0; i < *idx; i++) /* reverse to correct order */
a[*idx - 1 - i] = tmp[i];
}
64/32-bit Version w/Preprocessor Directives
You can accomplish the same thing for x86, while preserving the original types for x86_64 through the use of preprocessor directives. (understanding that there is actually no storage benefit -- long (8-bit on x86_64), long long (8-bit on x86)).
#include <stdio.h>
#include <stdlib.h>
#if defined(__LP64__) || defined(_LP64)
# define BUILD_64 1
#endif
#define MAXDIG 32
#ifdef BUILD_64
void digits2array (long x, long *a, size_t *idx);
int digits2array_rev (long x, long *a, size_t *i);
#else
void digits2array (long long x, long long *a, size_t *idx);
long long digits2array_rev (long long x, long long *a, size_t *i);
#endif
int main (void) {
#ifdef BUILD_64
long n = 25464878454;
long ar[MAXDIG] = {0};
#else
long long n = 25464878454;
long long ar[MAXDIG] = {0};
#endif
size_t idx = 0;
int i = 0;
digits2array (n, ar, &idx); /* convert n to array */
printf ("\n array:\n\n");
for (i = 0; i < idx; i++) /* output results */
#ifdef BUILD_64
printf (" ar[%2d] : %ld\n", i, ar[i]);
#else
printf (" ar[%2d] : %lld\n", i, ar[i]);
#endif
return 0;
}
/* converts x to array of digits in a (reverse order) */
#ifdef BUILD_64
int digits2array_rev (long x, long *a, size_t *i)
#else
long long digits2array_rev (long long x, long long *a, size_t *i)
#endif
{
if (x < 10) {
a[(*i)++] = x;
return x;
}
a[(*i)++] = x % 10;
return digits2array_rev (x / 10, a, i);
}
/* helper function to reverse results of digits2array_rev */
#ifdef BUILD_64
void digits2array (long x, long *a, size_t *idx)
{
long tmp[MAXDIG] = {0};
#else
void digits2array (long long x, long long *a, size_t *idx)
{
long long tmp[MAXDIG] = {0};
#endif
int i = 0;
digits2array_rev (x, tmp, idx); /* fill array with digits (reversed) */
for (i = 0; i < *idx; i++) /* reverse to correct order */
a[*idx - 1 - i] = tmp[i];
}