Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #42767 > unrolled thread

Request for source code review of simple Ising model

Started byUdyant Wig <udyant@panda.goosenet.in>
First post2014-04-10 23:38 +0530
Last post2014-04-20 11:46 +0530
Articles 20 on this page of 88 — 16 participants

Back to article view | Back to comp.lang.c


Contents

  Request for source code review of simple Ising model Udyant Wig <udyant@panda.goosenet.in> - 2014-04-10 23:38 +0530
    Re: Request for source code review of simple Ising model Malcolm McLean <malcolm.mclean5@btinternet.com> - 2014-04-10 13:30 -0700
      Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-12 00:34 +0530
        Re: Request for source code review of simple Ising model Malcolm McLean <malcolm.mclean5@btinternet.com> - 2014-04-11 12:25 -0700
        Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-16 01:12 +0530
          Re: Request for source code review of simple Ising model Ben Bacarisse <ben.usenet@bsb.me.uk> - 2014-04-16 01:33 +0100
            Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-16 17:57 +0530
              Re: Request for source code review of simple Ising model Malcolm McLean <malcolm.mclean5@btinternet.com> - 2014-04-16 06:00 -0700
              Re: Request for source code review of simple Ising model James Kuyper <jameskuyper@verizon.net> - 2014-04-16 10:58 -0400
                Re: Request for source code review of simple Ising model Keith Thompson <kst-u@mib.org> - 2014-04-16 09:07 -0700
                  Re: Request for source code review of simple Ising model James Kuyper <jameskuyper@verizon.net> - 2014-04-16 12:22 -0400
                    Re: Request for source code review of simple Ising model Keith Thompson <kst-u@mib.org> - 2014-04-16 10:38 -0700
                      Re: Request for source code review of simple Ising model Kaz Kylheku <kaz@kylheku.com> - 2014-04-16 19:37 +0000
                  Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-17 12:00 +0530
                    Re: Request for source code review of simple Ising model glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2014-04-17 09:32 +0000
                      Re: Request for source code review of simple Ising model "BartC" <bc@freeuk.com> - 2014-04-17 12:24 +0100
                        Re: Request for source code review of simple Ising model Keith Thompson <kst-u@mib.org> - 2014-04-17 08:16 -0700
                      Re: Request for source code review of simple Ising model Malcolm McLean <malcolm.mclean5@btinternet.com> - 2014-04-17 04:41 -0700
                        Re: Request for source code review of simple Ising model Les Cargill <lcargill99@comcast.com> - 2014-04-17 07:49 -0500
                    Re: Request for source code review of simple Ising model Keith Thompson <kst-u@mib.org> - 2014-04-17 08:00 -0700
                      Re: Request for source code review of simple Ising model Kaz Kylheku <kaz@kylheku.com> - 2014-04-17 15:06 +0000
                        Re: Request for source code review of simple Ising model Tim Rentsch <txr@alumni.caltech.edu> - 2014-04-18 21:04 -0700
                      Re: Request for source code review of simple Ising model glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2014-04-17 18:38 +0000
                        Re: Request for source code review of simple Ising model James Kuyper <jameskuyper@verizon.net> - 2014-04-17 15:26 -0400
                          Re: Request for source code review of simple Ising model "BartC" <bc@freeuk.com> - 2014-04-17 21:00 +0100
                            Re: Request for source code review of simple Ising model James Kuyper <jameskuyper@verizon.net> - 2014-04-17 16:34 -0400
                            Re: Request for source code review of simple Ising model glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2014-04-18 04:31 +0000
                        Re: Request for source code review of simple Ising model Keith Thompson <kst-u@mib.org> - 2014-04-17 14:05 -0700
                          Re: Request for source code review of simple Ising model Keith Thompson <kst-u@mib.org> - 2014-04-17 17:06 -0700
                          Re: Request for source code review of simple Ising model glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2014-04-18 04:54 +0000
                          Re: Request for source code review of simple Ising model Tim Rentsch <txr@alumni.caltech.edu> - 2014-04-18 11:51 -0700
                Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-17 11:42 +0530
              Re: Request for source code review of simple Ising model Ben Bacarisse <ben.usenet@bsb.me.uk> - 2014-04-16 16:54 +0100
                Re: Request for source code review of simple Ising model Malcolm McLean <malcolm.mclean5@btinternet.com> - 2014-04-16 15:22 -0700
                Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-17 13:03 +0530
                  Re: Request for source code review of simple Ising model Keith Thompson <kst-u@mib.org> - 2014-04-17 08:44 -0700
                    Re: Request for source code review of simple Ising model James Kuyper <jameskuyper@verizon.net> - 2014-04-17 12:12 -0400
                      Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-18 12:38 +0530
                      Re: Request for source code review of simple Ising model Malcolm McLean <malcolm.mclean5@btinternet.com> - 2014-04-18 03:11 -0700
                    Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-18 12:32 +0530
                      Re: Request for source code review of simple Ising model James Kuyper <jameskuyper@verizon.net> - 2014-04-18 10:05 -0400
          Re: Request for source code review of simple Ising model Ike Naar <ike@iceland.freeshell.org> - 2014-04-16 07:10 +0000
          Re: Request for source code review of simple Ising model James Kuyper <jameskuyper@verizon.net> - 2014-04-17 13:10 -0400
            Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-18 18:24 +0530
              Re: Request for source code review of simple Ising model James Kuyper <jameskuyper@verizon.net> - 2014-04-18 09:52 -0400
                Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-18 20:04 +0530
                  Re: Request for source code review of simple Ising model James Kuyper <jameskuyper@verizon.net> - 2014-04-18 11:00 -0400
                    Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-20 01:49 +0530
                      Re: Request for source code review of simple Ising model glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2014-04-19 21:20 +0000
                        Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-20 11:11 +0530
                          Re: Request for source code review of simple Ising model Richard Damon <Richard@Damon-Family.org> - 2014-04-20 09:06 -0400
                        Re: Request for source code review of simple Ising model James Kuyper <jameskuyper@verizon.net> - 2014-04-20 10:50 -0400
                          Re: Request for source code review of simple Ising model Malcolm McLean <malcolm.mclean5@btinternet.com> - 2014-04-21 09:14 -0700
                Re: Request for source code review of simple Ising model Ike Naar <ike@iceland.freeshell.org> - 2014-04-19 05:43 +0000
              Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-18 19:47 +0530
              Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-21 01:21 +0530
                Re: Request for source code review of simple Ising model Keith Thompson <kst-u@mib.org> - 2014-04-20 14:24 -0700
                  Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-21 10:40 +0530
                Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-21 12:29 +0530
            Re: Request for source code review of simple Ising model Keith Thompson <kst-u@mib.org> - 2014-04-18 08:36 -0700
              Re: Request for source code review of simple Ising model James Kuyper <jameskuyper@verizon.net> - 2014-04-18 13:40 -0400
                Re: Request for source code review of simple Ising model Keith Thompson <kst-u@mib.org> - 2014-04-18 11:14 -0700
                Re: Request for source code review of simple Ising model Malcolm McLean <malcolm.mclean5@btinternet.com> - 2014-04-18 13:55 -0700
              Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-19 01:25 +0530
                Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-19 01:44 +0530
                Re: Request for source code review of simple Ising model Kaz Kylheku <kaz@kylheku.com> - 2014-04-18 20:24 +0000
                Re: Request for source code review of simple Ising model Keith Thompson <kst-u@mib.org> - 2014-04-18 13:36 -0700
                  Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-19 20:18 +0530
                Re: Request for source code review of simple Ising model Richard <rgrdev_@gmail.com> - 2014-04-19 14:55 +0100
                  Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-20 02:10 +0530
              Re: Request for source code review of simple Ising model Ike Naar <ike@iceland.freeshell.org> - 2014-04-19 05:40 +0000
                Re: Request for source code review of simple Ising model Keith Thompson <kst-u@mib.org> - 2014-04-19 14:39 -0700
                  Re: Request for source code review of simple Ising model Ian Collins <ian-news@hotmail.com> - 2014-04-20 10:44 +1200
                    Re: Request for source code review of simple Ising model Keith Thompson <kst-u@mib.org> - 2014-04-19 17:11 -0700
                    Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-20 11:24 +0530
                  Re: Request for source code review of simple Ising model Keith Thompson <kst-u@mib.org> - 2014-04-19 17:19 -0700
                    Re: Request for source code review of simple Ising model Ike Naar <ike@iceland.freeshell.org> - 2014-04-20 10:10 +0000
                      Re: Request for source code review of simple Ising model Keith Thompson <kst-u@mib.org> - 2014-04-20 14:21 -0700
                        Re: Request for source code review of simple Ising model Ike Naar <ike@iceland.freeshell.org> - 2014-04-20 22:18 +0000
                          Re: Request for source code review of simple Ising model Keith Thompson <kst-u@mib.org> - 2014-04-20 19:27 -0700
                            Re: Request for source code review of simple Ising model Ike Naar <ike@iceland.freeshell.org> - 2014-04-21 12:38 +0000
                            Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-21 18:12 +0530
                            Re: Request for source code review of simple Ising model Ike Naar <ike@iceland.freeshell.org> - 2014-04-21 13:13 +0000
                              Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-21 19:46 +0530
                              Re: Request for source code review of simple Ising model Keith Thompson <kst-u@mib.org> - 2014-04-21 09:06 -0700
                  Re: Request for source code review of simple Ising model jacob navia <jacob@spamsink.net> - 2014-04-21 00:26 +0200
          Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-18 01:15 +0530
          Re: Request for source code review of simple Ising model Udyant Wig <udyantw@gmail.com> - 2014-04-20 11:46 +0530

Page 1 of 5  [1] 2 3 4 5  Next page →


#42767 — Request for source code review of simple Ising model

FromUdyant Wig <udyant@panda.goosenet.in>
Date2014-04-10 23:38 +0530
SubjectRequest for source code review of simple Ising model
Message-ID<87txa112hs.fsf@panda.goosenet.in>
While browsing around the Physics Stack Exchange, I came across an
answer by Ron Maimon*, and I saw that I could implement the simulation
described therein.  I first did a version in Emacs Lisp, on reviewing
which I felt that I could develop a version in C, using the Emacs Lisp
version as a rough guide.

I quote from the README:

    Briefly, the Ising model is a theoretical description of
    ferromagnetism, which arises when the magnetic moments of atomic
    spins align in the same direction.  It is used to study phase
    transitions and the emergence of equilibrium configurations.

I have not gone into the physics at all.  I only model the changing
configurations of a lattice of bits.

A copy of the program is at Bitbucket at this URL:
https://bitbucket.org/udyant/simplified-square-lattice-ising-model/src

I have used the implementation of linked lists from  kazlib  written by
Kaz Kylheku, and found at this URL:

                http://www.kylheku.com/~kaz/kazlib.html

The source code is used under the BSD license mentioned within them.
The license is reproduced below:

  Copyright 1996-2012
  Kaz Kylheku <kaz@kylheku.com>
  Vancouver, Canada
  All rights reserved.

  BSD License:

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:

    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in
       the documentation and/or other materials provided with the
       distribution.
    3. The name of the author may not be used to endorse or promote
       products derived from this software without specific prior
       written permission.

  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

I would like to request the readers to go over the source and suggest
any improvements to layout, style, structure, etc.  I would be highly
appreciative and very grateful.

The amalgamated source is about 628 lines; I have spaced the modules by
two empty lines.


/* common.h begins */

#ifndef COMMON_H
#define COMMON_H

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>

extern double beta;
extern int dimension;
extern int scale;
extern int minority_size;

#endif

/* common.h ends */


/* common.c begins */

#include "common.h"

double beta = 0.5;
int dimension = 3;
int scale = 100;
int minority_size = 1;

/* common.c ends */


/* utilities.h begins */

#ifndef UTILITIES_H
#define UTILITIES_H

#include "common.h"

bool random_bit (void);
bool is_all_zeroes (char *string);
bool is_positive_integer (char *string);
int  how_many (const char *s, int c);
int  find (const char string [], char character, int offset);
char *copy_substring (char *substring, \
		      const char *string, \
		      size_t start, \
		      size_t end);

#endif

/* utilities.h ends */


/* utilities.c begins */

#include "utilities.h"

bool random_bit (void)
{
    return rand () % 2;
}    

bool is_all_zeroes (char *string)
{
    char *sp;

    for (sp = string; *sp != '\0'; sp++) {
	if (*sp != '0') {
	    return false;
	}
    }

    return true;
}    

bool is_positive_integer (char *string)
{
    char *sp;

    for (sp = string; *sp != '\0'; sp++) {
	if (!isdigit (*sp)) {
	    return false;
	}
    }

    return (is_all_zeroes (string) ? false : true);
}    

/* From /C: A Reference Manual/, 5th ed., by Harbison and Steele
 * page 352
 */
int how_many (const char *s, int c)
{
    int n = 0;
    if (c == 0) return 0;
    while (s) {
	s = strchr (s, c);
	if (s) n++, s++;
    }
    return n;
}    

int find (const char string [], char character, int offset)
{
    int length = strlen (string);
    int i;

    for (i = offset; i < length; i++) {
	if (string [i] == character)
	    return i;
    }

    return -1;
}    

char *copy_substring (char *substring, \
		      const char *string, \
		      size_t start, \
		      size_t end)
{
    size_t length = end - start + 1;

    errno = 0;
    substring = malloc (1 + length);
    if (substring == NULL) {
	fprintf (stderr, "copy_substring: %s\n", strerror (errno));
	exit (1);
    }

    strncpy (substring, string + start, length - 1);
    substring [length] = '\0';
    
    return substring;
}
    

/* utilities.c ends */


/* bits.h begins */

#ifndef BITS_H
#define BITS_H

#include "common.h"

struct bit {
    int x;
    int y;
    int energy;
    bool bitvalue;
};

typedef struct bit bit;

/* Bits */
bool bits_equal (bit one, bit two);
bool negate (bit *b);
bit  complement (bit *b);
void flip (bit *b);
void dump_bit (bit b);

/* Lattices */
bit  **allocate_lattice (bit **lattice);
void free_lattice (bit **lattice);
void print_lattice (bit **lattice);
bool lattices_equal (bit **a, bit **b);

#endif

/* bits.h ends */


/* bits.c begins */

#include "bits.h"

/* Bits */
bool bits_equal (bit one, bit two)
{
    return one.bitvalue == two.bitvalue;
}

bool negate (bit *b)
{
    return !b->bitvalue;
}

bit complement (bit *b)
{
    bit complement;

    complement.x = b->x;
    complement.y = b->y;
    complement.energy = b->energy;
    complement.bitvalue = negate (b);

    return complement;
}

void flip (bit *b)
{
    b->bitvalue = negate (b);
}    

void dump_bit (bit b)
{
    printf ("x := %d\n", b.x);
    printf ("y := %d\n", b.y);
    printf ("energy := %d\n", b.energy);
    printf ("bitvalue := %d\n", b.bitvalue);
}


/* Lattices */
bit **allocate_lattice (bit **lattice)
{
    /* bit **lattice; */
    int i;

    errno = 0;
    lattice = malloc (dimension * sizeof (bit *));
    if (lattice == NULL)
    {
	fprintf (stderr, "%s\n", strerror (errno));
	exit (1);
    }
    for (i = 0; i < dimension; i++)
    {
	lattice [i] = malloc (dimension * sizeof (bit));
	if (lattice [i] == NULL)
	{
	    fprintf (stderr, "%s\n", strerror (errno));
	    exit (1);
	}
    }

    return lattice;
}

void free_lattice (bit **lattice)
{
    int i;

    for (i = 0; i < dimension; i++) {
	free (lattice [i]);
    }
    
    free (lattice);
}

void print_lattice (bit **lattice)
{
    int i, j;

    for (i = 0; i < dimension; i++) {
	for (j = 0; j < dimension; j++) {
	    printf ("%d", (lattice [i] [j]).bitvalue);
	    /*
	      dump_bit (lattice [i] [j]);
	    */
	}
	putchar ('\n');
    }
}

bool lattices_equal (bit **a, bit **b)
{
    int i, j;
    bool equal = true;

    for (i = 0; i < dimension; i++) {
	for (j = 0; j < dimension; j++) {
	    if (!bits_equal (a [i] [j], b [i] [j]))
		equal = false;
	}
    }

    return equal;
}

/* bits.c ends */


/* ising.h begins */

#ifndef ISING_H
#define ISING_H

#include <math.h>
#include <time.h>

#include "common.h"
#include "bits.h"
#include "utilities.h"

#include "list.h"

/* Core */
void   check_and_collect_neighbor (list_t *neighborhood, int x, int y);
list_t *neighbors (list_t *neighborhood, bit b);
int    energy (bit b);
void   calculate_energies (void);
void   ising_flip (bit *b);
void   iterate (void);
void   print_iteration (const char *format_string, int count);

/* Housekeeping */
static void dump_neighbors (list_t *neighbors);
static int  count_ones (void);
static int  count_zeroes (void);

/* Error checking */
void minority_error (void);
void beta_error (void);
void dimension_error (void);

#endif

/* ising.h ends */


/* ising.c begins */

#include "ising.h"

static bit **ising_lattice;

const char initial_format [] = "Initial configuration %6d";
const char iteration_format [] = "Iteration %6d";
const char final_format [] = "Final configuration %6d";


/* Core */
void check_and_collect_neighbor (list_t *neighborhood, int x, int y)
{
    lnode_t *neighbor;
    bit *payload;
    
    if (x >= 0 && y >= 0 && x < dimension && y < dimension) {
	payload = &ising_lattice [x] [y];
	neighbor = lnode_create (payload);

	if (neighbor == NULL) {
	    fprintf (stderr, "%s\n", strerror (errno));
	    lnode_destroy (neighbor);
	    free (payload);
	    exit (1);
	}

	list_append (neighborhood, neighbor);
    }
}    

list_t *neighbors (list_t *neighborhood, bit b)
{
    neighborhood = list_create (-1);

    check_and_collect_neighbor (neighborhood, b.x, b.y - 1);
    check_and_collect_neighbor (neighborhood, b.x, b.y + 1);
    check_and_collect_neighbor (neighborhood, b.x - 1, b.y);
    check_and_collect_neighbor (neighborhood, b.x + 1, b.y);

    return neighborhood;
}

int energy (bit b)
{
    int e = 0;
    lnode_t *neighbor;
    bit *rover;
    list_t *neighborhood = NULL;

    neighborhood = neighbors (neighborhood, b);
    for (neighbor = list_first (neighborhood); neighbor != NULL; \
	 neighbor = list_next (neighborhood, neighbor)) {
	rover = lnode_get (neighbor);
	if (b.bitvalue != rover->bitvalue) {
	    e++;
	}
    }

    list_destroy_nodes (neighborhood);
    list_destroy (neighborhood);

    return e;
}    

void calculate_energies (void)
{
    int i, j;
    
    for (i = 0; i < dimension; i++) {
	for (j = 0; j < dimension; j++) {
	    (ising_lattice [i] [j]).energy = energy (ising_lattice [i] [j]);
	}
    }
}

void ising_flip (bit *b)
{
    int old_energy = b->energy;
    int new_energy = energy (complement (b));
    int delta_energy = new_energy - old_energy;

    if  (delta_energy > 0) {
	double ising_threshold = exp (-(beta * delta_energy));
	double random_value = rand () % scale / (double) scale;

	if (ising_threshold < random_value) {
	    flip (b);
	}
    }
    else {
	flip (b);
    }
}    

void iterate (void)
{
    int x = (int) rand () % dimension;
    int y = (int) rand () % dimension;

    ising_flip (&ising_lattice [x] [y]);
    calculate_energies ();
}

void print_iteration (const char *format_string, int count)
{
    size_t i;
    size_t length = strlen (format_string);
    
    putchar ('\n');
    printf (format_string, count);
    putchar ('\n');
    for (i = 0; i < length + 3; i++)
	putchar ('-');
    putchar ('\n');
    print_lattice (ising_lattice);
}


/* Housekeeping */
static void dump_neighbors (list_t *neighbors)
{
    bit *rover;
    lnode_t *neighbor;
    
    for (neighbor = list_first (neighbors); neighbor != NULL; \
	 neighbor = list_next (neighbors, neighbor)) {
	rover = lnode_get (neighbor);
	dump_bit (*rover);
    }
}

static int count_ones (void)
{
    int count = 0;
    int i, j;

    for (i = 0; i < dimension; i++) {
	for (j = 0; j < dimension; j++) {
	    if ((ising_lattice [i] [j]).bitvalue == true) {
		count++;
	    }
	}
    }

    return count;
}    

static int count_zeroes (void)
{
    int count = 0;
    int i, j;

    for (i = 0; i < dimension; i++) {
	for (j = 0; j < dimension; j++) {
	    if ((ising_lattice [i] [j]).bitvalue == false) {
		count++;
	    }
	}
    }

    return count;
}    


/* Error checking */
void minority_error (void)
{
    fputs ("minority_size <argv [3]> is not a nonnegative integer\n", stderr);
    exit (2);
}

void beta_error (void)
{
    fputs ("beta <argv [2]> is not positive floating-point number.\n", stderr);
    exit (2);
}

void dimension_error (void)
{
    fputs ("dimension <argv [1]> is not a nonnegative integer.\n", stderr);
    exit (2);
}    


/* Return codes:
 * 0    Successful execution
 * 1    Memory allocation failed
 * 2    Wrong form of argument
 */
int main (int argc, char *argv [])
{
    if (argc > 3) {
	if (is_positive_integer (argv [3]) || is_all_zeroes (argv [3])) {
	    minority_size = atoi (argv [3]);
	}
	else {
	    minority_error ();
	}
	
	if (minority_size < 0) {
	    minority_size = 0;
	}
	else if (minority_size > dimension * dimension) {
	    minority_size = dimension * dimension;
	}
	else if (minority_size > (dimension * dimension) / 2) {
	    minority_size = (dimension * dimension) - minority_size;
	}
    }
    if (argc > 2) {
	char *beta_string = argv [2];
	size_t length = strlen (beta_string);
	
	if (how_many (beta_string, '.') == 1) {
	    int position_decimal = find (beta_string, '.', 0);
	    char *integral_part = NULL;
	    char *fractional_part = NULL;

	    integral_part = copy_substring (integral_part, \
					    beta_string, \
					    0, \
					    position_decimal - 1);
	    if (is_positive_integer (integral_part) || \
		is_all_zeroes (integral_part)) {
		fractional_part = copy_substring (fractional_part, \
						  beta_string, \
						  position_decimal + 1, \
						  length - 1);
		if (is_positive_integer (fractional_part) || \
		    is_all_zeroes (fractional_part)) {
		    beta = atof (argv [2]);
		}
		else {
		    beta_error ();
		}

		free (fractional_part);
	    }
	    else {
		beta_error ();
	    }

	    free (integral_part);
	}
	else {
	    beta_error ();
	}
    }
    if (argc > 1) {
	if (is_positive_integer (argv [1]))
	    dimension = atoi (argv [1]);
	else {
	    dimension_error ();
	}
    }

    srand (time (0));

    int i, j;
    bit b;
    
    /* Allocate the square Ising lattice */
    ising_lattice = allocate_lattice (ising_lattice);
    for (i = 0; i < dimension; i++) {
	for (j = 0; j < dimension; j++) {
	    b.x = i;
	    b.y = j;
	    b.energy = 0;
	    b.bitvalue = random_bit ();

	    ising_lattice [i] [j] = b;
	}
    }
    calculate_energies ();


    /* Begin simulation */
    print_iteration (initial_format, 0);

    long k = 1;
    while (true) {
	if ((count_zeroes () == minority_size) || \
	    (count_ones () == minority_size)) {
	    break;
	}
	iterate ();
	print_iteration (iteration_format, k++);
    }
    print_iteration (final_format, k);


    /* End simulation */
    free_lattice (ising_lattice);
    exit (0);
}    


/* ising.c ends */


The answer mentioned earlier:
* Ron Maimon (http://physics.stackexchange.com/users/4864/ron-maimon),
How do you start self-learning physics, URL (version: 2012-07-31):
http://physics.stackexchange.com/q/33223


Udyant Wig, programming novice 

[toc] | [next] | [standalone]


#42783

FromMalcolm McLean <malcolm.mclean5@btinternet.com>
Date2014-04-10 13:30 -0700
Message-ID<349e1afe-6f59-4387-8eef-c29d57682750@googlegroups.com>
In reply to#42767
On Thursday, April 10, 2014 7:08:31 PM UTC+1, Udyant Wig wrote:
> While browsing around the Physics Stack Exchange, I came across an
> answer by Ron Maimon*, and I saw that I could implement the simulation
> described therein.  I first did a version in Emacs Lisp, on reviewing
> which I felt that I could develop a version in C, using the Emacs Lisp
> version as a rough guide.
> 
Lisp is for expressing programming ideas in a flexible, elegant way. C is for
bit bashing. Whilst you can take Lisp constructs and translate them into
C equivalents, you're not really using the language as intended.

In C, and Ising model is something like

typedef struct
{
  int width;
  int height;
  unsigned char *mesh;
  double energy;
  
} ISING;

To make it easy, use one byte per cell.
Set one up by calling malloc to allocate width * height bytes. Set them to 
an initial value, eg 1 or 0 with a 50% chance of each. Do this by stepping
through the mesh with a for loop. 
To access an element, do

model->mesh[y*model->width+x];

Nowadays compilers will generate very efficient code for this. In the bad old days you had to do tricks to prevent unnecessary multiplies. You might like to 
move the y * mesh->width out of the inner loop and use an increment for the x
step to see if it makes any difference on your system.
C is all about very tight loops stepping through arrays, and doing simple
operations on them.

For an Ising model, you need special code for the boundary. So go from y= 1 to height -2, x = 1 to width -2, count the neighbouring cells, and set the second
bit (cell |= 0x02 to set  or cell &= ~0x02 to clear) to indicate the next 
state. Then go through the edges applying special rules for the edge
conditions. Then you cna either keep a flag indicating that bit 0 or bit
1 is current, or you can step through again and set bit 0 to bit 1 (
cell >>= 1 or cell = (cell & 0x02) ? 1 : 0; )

If you write C idiomatically and half way efficiently, it is lightening
fast. You can step a thousand by a thousand Ising model, probably in about
a millisecond.  

[toc] | [prev] | [next] | [standalone]


#42811

FromUdyant Wig <udyantw@gmail.com>
Date2014-04-12 00:34 +0530
Message-ID<87wqev6631.fsf@panda.goosenet.in>
In reply to#42783
Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
| Lisp is for expressing programming ideas in a flexible, elegant way. C
| is for bit bashing. Whilst you can take Lisp constructs and translate
| them into C equivalents, you're not really using the language as
| intended.

 I take it that the code I posted does not behoove a native speaker of
 C, and that I attempted to speak with a Lisp accent.  Since I did not
 have experience with bit-mangling (in any language), I had not thought
 of a bit-mangling solution.
 
| In C, and Ising model is something like
|
| typedef struct
| {
|   int width;
|   int height;
|   unsigned char *mesh;
|   double energy;
|   
| } ISING;

 This is one place that puzzled me.  I quote from the Physics Stack
 Exchange answer that I linked to:

    Make a 2d grid of bits with value 0 or 1. Choose a bit at random,
    and calculate the energy it feels with its neighbors, by counting
    the number of neighbors that have a different bit value. The energy
    is this number.

 As I read it, each cell has its own energy, not the entire mesh.  I
 cannot see how to handle the energy of each individual cell using the
 above struct.
 
| To make it easy, use one byte per cell.  Set one up by calling malloc
| to allocate width * height bytes. Set them to an initial value, eg 1
| or 0 with a 50% chance of each. Do this by stepping through the mesh
| with a for loop.  To access an element, do
|
| model->mesh[y*model->width+x];

 Is faking a multidimensional array by a vector always deemed good (read
 "efficient")?  When should one use multidimensional arrays and when
 should one fake them by vectors and manual subscripting?
 
| Nowadays compilers will generate very efficient code for this. In the
| bad old days you had to do tricks to prevent unnecessary
| multiplies. You might like to move the y * mesh->width out of the
| inner loop and use an increment for the x step to see if it makes any
| difference on your system.

 I will look into this.
 
| C is all about very tight loops stepping through arrays, and doing
| simple operations on them.

 A philosophical point I will remember.
 
| For an Ising model, you need special code for the boundary. So go from
| y= 1 to height -2, x = 1 to width -2, count the neighbouring cells,
| and set the second bit (cell |= 0x02 to set or cell &= ~0x02 to clear)
| to indicate the next state. Then go through the edges applying special
| rules for the edge conditions. Then you cna either keep a flag
| indicating that bit 0 or bit 1 is current, or you can step through
| again and set bit 0 to bit 1 ( cell >>= 1 or cell = (cell & 0x02) ? 1
| : 0; )

 I found this to be clever and elegant.
 
| If you write C idiomatically and half way efficiently, it is
| lightening fast. You can step a thousand by a thousand Ising model,
| probably in about a millisecond.

 I ran my program for some minutes with a 1000x1000 lattice, a very low
 value of beta (which encourages rapid change; high values tend to
 increase the "inertia" of the system), and a cutoff size of 1000, which
 means that if the lattice contains either 1000 ones or 1000 zeroes out
 of all the bits, then the simulation is finished.  I closed it manually
 because I did not see it ending any time soon.

 If I can adopt some of the bit-mangling ideas, then perhaps the
 situation might change.

 The comments and ideas were valued very much.

 Udyant Wig

[toc] | [prev] | [next] | [standalone]


#42812

FromMalcolm McLean <malcolm.mclean5@btinternet.com>
Date2014-04-11 12:25 -0700
Message-ID<f9f921e5-10fe-48fb-b255-4ad1918f722c@googlegroups.com>
In reply to#42811
On Friday, April 11, 2014 8:04:18 PM UTC+1, Udyant Wig wrote:
> Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
> 
>  Is faking a multidimensional array by a vector always deemed good (read
>  "efficient")?  When should one use multidimensional arrays and when
>  should one fake them by vectors and manual subscripting?
> 
It's a deficiency in the language. It doesn't have good facilities for multi-dimensional arrays. That was largely alleviated in C99, but the standard wasn't widely implemented.
If you don't know array dimensions at compile time, or if you have to pass the array to subroutines which are best written as taking an variable mxn array rather than a fixed-size one, then it's
easier to allocate a 1D array and do the calculations explicitly. 

[toc] | [prev] | [next] | [standalone]


#42989

FromUdyant Wig <udyantw@gmail.com>
Date2014-04-16 01:12 +0530
Message-ID<87a9bm5qhb.fsf@panda.goosenet.in>
In reply to#42811
  Over the past few days, I have revised and rewritten the program to
  use a vector of unsigned characters (i.e., an 8-bit byte) for the data
  representation of a square-lattice Ising model:

          7  6  5  4  3  2  1  0
        *--*--*--*--*--*--*--*--*
	|X |X |X |E |E |E |NS|CS|
	*__*__*__*__*__*__*__*__*

CS := bitvalue of this cell in the current state
NS := bitvalue of this cell in the next state
E  := binary representation of energy: 0 to 4
X  := unused

  Testing shows that this version is a bit faster than the one I posted
  earlier.  It is also shorter in terms of code.  But it still takes
  quite a long time for 10x10 lattices.

  The source and Makefile follow:
  

/* common.h begins */

#ifndef COMMON_H
#define COMMON_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include <stdbool.h>
#include <time.h>
#include <ctype.h>

#endif

/* common.h ends */


/* utilities.h begins */

#ifndef UTILITIES_H
#define UTILITIES_H

#include "common.h"

bool is_all_zeroes (char *string);
bool is_positive_integer (char *string);
int  how_many (const char *s, int c);
int  find (const char string [], char character, int offset);
char *copy_substring (char *substring, const char *string, size_t start, size_t end);

#endif

/* utilities.h ends */


/* utilities.c begins */

#include "utilities.h"

bool is_all_zeroes (char *string)
{
    char *sp;

    for (sp = string; *sp != '\0'; sp++) {
	if (*sp != '0') {
	    return false;
	}
    }

    return true;
}    

bool is_positive_integer (char *string)
{
    char *sp;

    for (sp = string; *sp != '\0'; sp++) {
	if (!isdigit (*sp)) {
	    return false;
	}
    }

    return (is_all_zeroes (string) ? false : true);
}    

/* From /C: A Reference Manual/, 5th ed., by Harbison and Steele
 * page 352
 */
int how_many (const char *s, int c)
{
    int n = 0;
    if (c == 0) return 0;
    while (s) {
	s = strchr (s, c);
	if (s) n++, s++;
    }
    return n;
}    

int find (const char string [], char character, int offset)
{
    int length = strlen (string);
    int i;

    for (i = offset; i < length; i++) {
	if (string [i] == character)
	    return i;
    }

    return -1;
}    

char *copy_substring (char *substring, const char *string, size_t start, size_t end)
{
    size_t length = end - start + 1;

    errno = 0;
    substring = malloc (1 + length);
    if (substring == NULL) {
	fprintf (stderr, "copy_substring: %s\n", strerror (errno));
	exit (1);
    }

    strncpy (substring, string + start, length - 1);
    substring [length] = '\0';
    
    return substring;
}

/* utilities.c ends */


/* bitsing.h begins */

#ifndef BITSING_H
#define BITSING_H

typedef unsigned char byte;

/* Lattice */
byte *allocate_lattice (byte *lattice);
void initialize_lattice (void);
void print_lattice (void);

/* Core */
int  check_and_add_neighbor (byte cell, int col, int row);
void next_state (void);

/* Miscellaneous */
int  count_ones (void);
void print_iteration (const char *format_string, int count);

/* Error checking */
void minority_error (void);
void beta_error (void);
void dimension_error (void);

#endif

/* bitsing.h ends */


/* bitsing.c begins */

#include "common.h"
#include "bitsing.h"
#include "utilities.h"

#define ENERGY_MASK 0x1c

static int    dimension		= 3;
static double beta		= 0.5;
static int    minority_size	= 1;

static byte *lattice;


/* Lattice */
byte *allocate_lattice (byte *lattice)
{
    errno = 0;
    lattice = malloc (dimension * dimension * sizeof *lattice);
    if (lattice == NULL) {
	fprintf (stderr, "allocate_lattice: %s\n", strerror (errno));
	exit (1);
    }

    return lattice;
}

void initialize_lattice (void)
{
    int row, col;
    byte *cell;

    for (col = 0; col < dimension; col++) {
	for (row = 0; row < dimension; row++) {
	    cell = &lattice [col * dimension + row];
	    /* Clear second bit */
	    *cell &= ~0x02;
	    /* Set second bit randomly  */
	    *cell |= ((byte) (rand () % 2)) << 1; 
	}
    }
}    

void print_lattice (void)
{
    int row, col;

    for (col = 0; col < dimension; col++) {
	for (row = 0; row < dimension; row++) {
	    printf ("%d", lattice [col * dimension + row] & 0x01);
	}
	putchar ('\n');
    }
}


/* Core */
int check_and_add_neighbor (byte cell, int col, int row)
{
    byte neighbor;
    if (0 <= col && 0 <= row && col < dimension && row < dimension) {
	neighbor = lattice [col * dimension + row];
	return ((cell & 0x02) ^ (neighbor & 0x02));
    }
    return 0;
}

void next_state (void)
{
    int row, col;
    byte *cell;

    for (col = 0; col < dimension; col++)    {
	for (row = 0; row < dimension; row++) {
	    cell = &lattice [col * dimension + row];
	    *cell |= (0x01 & ((*cell & 0x02) >> 1));
	}
    }
}    


/* Miscellaneous */
int count_ones (void)
{
    int count = 0;
    int row, col;

    for (col = 0; col < dimension; col++) {
	for (row = 0; row < dimension; row++) {
	    if ((lattice [col * dimension + row] & 0x01) == (byte) 1) {
		count++;
	    }
	}
    }

    return count;
}

static const char initial_format [] = \
    "Initial configuration %6d\n----------------------------\n";
static const char iteration_format [] = \
    "Iteration %6d\n----------------\n";
static const char final_format [] = \
    "Final configuration %6d\n--------------------------\n";

void print_iteration (const char *format_string, int count)
{
    putchar ('\n');
    printf (format_string, count);
    print_lattice ();
}


/* Error checking */
void minority_error (void)
{
    fputs ("minority_size <argv [3]> is not a nonnegative integer\n", stderr);
    exit (2);
}

void beta_error (void)
{
    fputs ("beta <argv [2]> is not positive floating-point number.\n", stderr);
    exit (2);
}

void dimension_error (void)
{
    fputs ("dimension <argv [1]> is not a nonnegative integer.\n", stderr);
    exit (2);
}    


/* Return codes:
 * 0 -- success
 * 1 -- memory allocation failure
 * 2 -- invalid command line argument
 */
int main (int argc, char *argv [])
{
    if (argc > 3) {
	if (is_positive_integer (argv [3]) || is_all_zeroes (argv [3])) {
	    minority_size = atoi (argv [3]);
	}
	else {
	    minority_error ();
	}
	
	if (minority_size < 0) {
	    minority_size = 0;
	}
	else if (minority_size > dimension * dimension) {
	    minority_size = dimension * dimension;
	}
	else if (minority_size > (dimension * dimension) / 2) {
	    minority_size = (dimension * dimension) - minority_size;
	}
    }
    if (argc > 2) {
	char *beta_string = argv [2];
	size_t length = strlen (beta_string);
	
	if (how_many (beta_string, '.') == 1) {
	    int position_decimal = find (beta_string, '.', 0);
	    char *integral_part = NULL;
	    char *fractional_part = NULL;

	    integral_part = copy_substring (integral_part, \
					    beta_string, \
					    0, \
					    position_decimal - 1);
	    if (is_positive_integer (integral_part) || \
		is_all_zeroes (integral_part)) {
		fractional_part = copy_substring (fractional_part, \
						  beta_string, \
						  position_decimal + 1, \
						  length - 1);
		if (is_positive_integer (fractional_part) || \
		    is_all_zeroes (fractional_part)) {
		    beta = atof (argv [2]);
		}
		else {
		    beta_error ();
		}

		free (fractional_part);
	    }
	    else {
		beta_error ();
	    }

	    free (integral_part);
	}
	else {
	    beta_error ();
	}
    }
    if (argc > 1) {
	if (is_positive_integer (argv [1]))
	    dimension = atoi (argv [1]);
	else {
	    dimension_error ();
	}
    }

    srand (time (0));
    
    lattice = allocate_lattice (lattice);
    initialize_lattice ();
    next_state ();
    print_iteration (initial_format, 0);

    long count = 1;
    while (true) {
	int rrow, rcol;
	byte rcell, ccell;
	int old_energy;
	int new_energy;
	int delta;

	rrow = rand () % dimension;
	rcol = rand () % dimension;
	rcell = lattice [rcol * dimension + rrow];
	ccell = (rcell ^ 0x02) & 0x02;	/* comlemented cell */
	old_energy = (rcell & ENERGY_MASK) >> 2;

	new_energy = check_and_add_neighbor (ccell, rrow - 1, rcol);
	new_energy = check_and_add_neighbor (ccell, rrow + 1, rcol);
	new_energy = check_and_add_neighbor (ccell, rrow, rcol - 1);
	new_energy = check_and_add_neighbor (ccell, rrow, rcol + 1);
	
	delta = new_energy - old_energy;
	if (delta < 0) {
	    lattice [rcol * dimension + rrow] = ccell;
	    /* clear energy */
	    ccell &= ~ENERGY_MASK;	
	    /* set energy */
	    ccell |= (ENERGY_MASK & ((byte) new_energy << 2)); 
	}
	else {
	    double ising_window = exp (-(beta * delta));
	    double random_value = (double) (rand () % 100) / 100.0;

	    if (random_value < ising_window) {
		lattice [rcol * dimension + rrow] = ccell;
		/* clear energy */
		ccell &= ~ENERGY_MASK;
		/* set energy */
		ccell |= (ENERGY_MASK & ((byte) new_energy << 2)); 
	    }
	}

	print_iteration (iteration_format, count++);
	int ones_count = count_ones ();
	if ((ones_count == minority_size) || \
	    ((dimension * dimension - ones_count) == minority_size)) {
	    break;
	}

	next_state ();
    }

    print_iteration (final_format, count);
    free (lattice);
    exit (0);
}    

/* bitsing.c ends */


# Makefile begins 

CC = gcc
CFLAGS = -O0 -g -std=c99 -pedantic -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes

bitsing: bitsing.o bitsing.h common.h utilities.o utilities.h
	$(CC) $(CFLAGS) -o bitsing bitsing.o utilities.o -lm

depend: .depend
	$(CC) $(CFLAGS) -E -MM *.c > .depend

clean:
	rm *.o bitsing

# Makefile ends 


  Udyant Wig        

[toc] | [prev] | [next] | [standalone]


#42996

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2014-04-16 01:33 +0100
Message-ID<0.65e770be25e0037ff45a.20140416013306BST.87ioqayuyl.fsf@bsb.me.uk>
In reply to#42989
Udyant Wig <udyantw@gmail.com> writes:
<snip>
>   The source and Makefile follow:

There are a few things I find stylistically odd, but there is a more
significant issue that you should address: malloc does not initialise
the data it allocates.  Since your "initialize_lattice" function just
sets the cells based on their current content, at no time is the data
made determinate.  Obviously, you usually get zeros (your system may
even guarantee you get zeros) but C does not guarantee this.

Stylistically, I'd make more use of function arguments.  I'd make the
lattice an argument of the functions that work on it (the one place
where you do pass it, you don't make any use of it).

In several places (two where it might matter for speed) you could do
away with the nested loops and the index arithmetic.  Given your data,
this pattern:

     for (col = 0; col < dimension; col++) {
          for (row = 0; row < dimension; row++) {
              ... lattice[col * dimension + row]...
          }
     }

can often be replaced with a single loop.  You might even use a pointer:

  byte *bp = lattice, *end = bp + dimension * dimension;
  while (bp < end) {
       ... *bp++ ...
  }

Of course, the optimiser might do most of this anyway, so there may be
no gain at all.

You use a lot of functions (good) but despite having one for each
separate command-line error condition (I wouldn't, myself) you've put
all the main work into a giant loop in main.

Finally, a trick the often helps this sort of code is to over allocate
the array to leave a border of zero cells.  This means you can eliminate
the test for 'col' and 'row' being in bounds and sometimes this pays
dividends.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#43012

FromUdyant Wig <udyantw@gmail.com>
Date2014-04-16 17:57 +0530
Message-ID<878ur54fy1.fsf@panda.goosenet.in>
In reply to#42996
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:

| There are a few things I find stylistically odd, but there is a more
| significant issue that you should address: malloc does not initialise
| the data it allocates.  Since your "initialize_lattice" function just
| sets the cells based on their current content, at no time is the data
| made determinate.  Obviously, you usually get zeros (your system may
| even guarantee you get zeros) but C does not guarantee this.

 Should I have used calloc() or memset()?

 I did run the program through valgrind and it did report errors
 pertaining to uninitialized memory, but I thought that as I was never
 actually using or reading from the freshly allocated memory (it was set
 immediately afterwards in main()), all was well.  I could be mistaken.

| Stylistically, I'd make more use of function arguments.  I'd make the
| lattice an argument of the functions that work on it (the one place
| where you do pass it, you don't make any use of it).

 The only function where I pass it is allocate_lattice(), which takes as
 actual argument the global lattice pointer, calls malloc(), and returns
 it.  Should I have done the allocation in main() itself, omitting a
 separate allocator?

 I am still unclear as to the more general situation: given a global
 pointer, should its allocation be isolated in a function, and if so,
 what should it return?  Also, should whichever functions operating on
 the global take it as an argument or have at it directly?
 
| In several places (two where it might matter for speed) you could do
| away with the nested loops and the index arithmetic.  Given your data,
| this pattern:
|
|      for (col = 0; col < dimension; col++) {
|           for (row = 0; row < dimension; row++) {
|               ... lattice[col * dimension + row]...
|           }
|      }
|
| can often be replaced with a single loop.  You might even use a pointer:
|
|   byte *bp = lattice, *end = bp + dimension * dimension;
|   while (bp < end) {
|        ... *bp++ ...
|   }
|
| Of course, the optimiser might do most of this anyway, so there may be
| no gain at all.

 I replaced every set of nested loops (except the one in
 print_lattice(); I have yet to figure out the calculations to print a
 1D array onscreen as 2D) by the pointer loop, and I did see some
 quickening.  (I seeded the random number generator with an integer for
 the testing runs.)
 
| You use a lot of functions (good) but despite having one for each
| separate command-line error condition (I wouldn't, myself) you've put
| all the main work into a giant loop in main.

 Indeed.  I have now found that that giant loop can be shipped off into
 a new function, and said loop in main() can be replaced by a single
 function call.

 Why would you not have separate functions for command-line error
 conditions?
 
| Finally, a trick the often helps this sort of code is to over allocate
| the array to leave a border of zero cells.  This means you can eliminate
| the test for 'col' and 'row' being in bounds and sometimes this pays
| dividends.

 I tried doing that.  If the desired dimension was to be d, I had it
 allocate a (d + 2)*(d + 2) lattice.  I also figured out the starting
 and the ending positions of the actual lattice (which was a sublattice
 of the one allocated), but I found that the pointer loop I had
 substituted for nested loops would have to be changed so that the
 pointer roved only within the sublattice.

 Determining whether the benefits of having a zero-border and no
 boundary-checking four times for each randomly selected cell outweigh
 the cost of the calculations necessary to rove only in the sublattice
 is going to take quite a few profiled runs.


 Thank you for the feedback and commentary.  I am grateful.  I learned
 much.

 Udyant Wig

[toc] | [prev] | [next] | [standalone]


#43013

FromMalcolm McLean <malcolm.mclean5@btinternet.com>
Date2014-04-16 06:00 -0700
Message-ID<aa14979c-1126-4614-aed7-99a9d328d40d@googlegroups.com>
In reply to#43012
On Wednesday, April 16, 2014 1:27:50 PM UTC+1, Udyant Wig wrote:
> 
>  I am still unclear as to the more general situation: given a global
>  pointer, should its allocation be isolated in a function, and if so,
>  what should it return?  Also, should whichever functions operating on
>  the global take it as an argument or have at it directly?
> 
If caller has access to the global pointer, subroutines which operate on it should take the global as
a parameter.
So how can caller not have access to the global, given that by definition a global is accessible from
anywhere?  The answer is that often you want to hide the global from caller. e.g. a cursor is inherently
global, but often you want a function getcursorxy(int *x, int *y) which functions can just call, without
bothering about the cursor implementation details. 
However getcursorxy should be written like this

SCREEN *global_screen_setup;
void getcursoxy(int *x, int *y) 
{
   getscreencursorxy(global_screen_setup, x, y);
}

void getscreencursorx(SCREEN *screen, int *x, int *y)
{
  *x = screen->cursor_x;
  *y = screen->cursor_y;
}

You just want a few globals in your program, and you want to access them through a few carefully-
controlled access points. Then the program is less likely to get into a confusing and hard-to-debug 
state.

[toc] | [prev] | [next] | [standalone]


#43015

FromJames Kuyper <jameskuyper@verizon.net>
Date2014-04-16 10:58 -0400
Message-ID<534E9A83.70101@verizon.net>
In reply to#43012
On 04/16/2014 08:27 AM, Udyant Wig wrote:
> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
> 
> | There are a few things I find stylistically odd, but there is a more
> | significant issue that you should address: malloc does not initialise
> | the data it allocates.  Since your "initialize_lattice" function just
> | sets the cells based on their current content, at no time is the data
> | made determinate.  Obviously, you usually get zeros (your system may
> | even guarantee you get zeros) but C does not guarantee this.
> 
>  Should I have used calloc() or memset()?

calloc() is functionally equivalent to malloc() followed by memset().
There's no plausible reasons why calloc() would ever be significantly
slower than malloc()+memset(). However, on some systems, dynamically
allocated memory is automatically zeroed out, whether allocated by
calloc() or malloc() - on such systems, malloc()+memset() would be a
waste of time, so you should simply call calloc().

>  I did run the program through valgrind and it did report errors
>  pertaining to uninitialized memory, but I thought that as I was never
>  actually using or reading from the freshly allocated memory (it was set
>  immediately afterwards in main()), all was well.  I could be mistaken.

You are. main() doesn't do anything between calling allocate_lattice()
and initialize_lattice(). allocate_lattice() does nothing to initialize
the lattice (which make sense). initialize_lattice() doesn't do anything
before reaching the following line, to initialize *cell:

    *cell &= ~0x02;

Since that line is equivalent to

    *cell = *cell & ~0x02;

the second *cell reads the uninitialized memory allocated by
allocate_lattice().

> | Stylistically, I'd make more use of function arguments.  I'd make the
> | lattice an argument of the functions that work on it (the one place
> | where you do pass it, you don't make any use of it).
> 
>  The only function where I pass it is allocate_lattice(), which takes as
>  actual argument the global lattice pointer, calls malloc(), and returns
>  it.  Should I have done the allocation in main() itself, omitting a
>  separate allocator?
> 
>  I am still unclear as to the more general situation: given a global
>  pointer, should its allocation be isolated in a function, and if so,
>  what should it return?  Also, should whichever functions operating on
>  the global take it as an argument or have at it directly?

As a general rule, you should avoid globals - they make it harder to
keep track of which function is responsible for each change to the
global. I'd create the pointer at block scope in main(), and pass it to
all of the functions that need access for it. In a small program, it
doesn't make much difference. However, in a larger program passing
around the pointer explicitly makes it much easier to track down which
function is responsible for something happening.

There's another advantage: if at some future time you want to create a
modified version of your program that involves running two different
Ising models at the same time, with different parameters, in order to
compare the results, using pointers makes that easy. Using globals would
not.

[toc] | [prev] | [next] | [standalone]


#43017

FromKeith Thompson <kst-u@mib.org>
Date2014-04-16 09:07 -0700
Message-ID<lnr44x6ywl.fsf@nuthaus.mib.org>
In reply to#43015
James Kuyper <jameskuyper@verizon.net> writes:
> On 04/16/2014 08:27 AM, Udyant Wig wrote:
>> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>> 
>> | There are a few things I find stylistically odd, but there is a more
>> | significant issue that you should address: malloc does not initialise
>> | the data it allocates.  Since your "initialize_lattice" function just
>> | sets the cells based on their current content, at no time is the data
>> | made determinate.  Obviously, you usually get zeros (your system may
>> | even guarantee you get zeros) but C does not guarantee this.
>> 
>>  Should I have used calloc() or memset()?
>
> calloc() is functionally equivalent to malloc() followed by memset().
> There's no plausible reasons why calloc() would ever be significantly
> slower than malloc()+memset(). However, on some systems, dynamically
> allocated memory is automatically zeroed out, whether allocated by
> calloc() or malloc() - on such systems, malloc()+memset() would be a
> waste of time, so you should simply call calloc().
[...]

Either calloc() or memset() can be used to initialize the block of
memory to all-bits-zero, but that's not necessarily as useful as you
might expect.  There's no guarantee in the language that setting a
floating-point or pointer object to all-bits-zero will set it to 0.0 or
NULL, respectively (though it very commonly will).

If you don't mind making your code a bit non-portable (and in fact
systems where 0.0 and NULL *aren't* represented as all-bits-zero are
rare), then calloc() or memset() can be reasonable.  It will at least
make the initial contents of the allocated memory consistent, even if
it's not necessarily correct.

An alternative is to carefully write your code so that it never accesses
memory before it's been explicitly initialized to some meaningful value.
(Valgrind can help with that.)

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#43019

FromJames Kuyper <jameskuyper@verizon.net>
Date2014-04-16 12:22 -0400
Message-ID<534EAE51.9070304@verizon.net>
In reply to#43017
On 04/16/2014 12:07 PM, Keith Thompson wrote:
...
> Either calloc() or memset() can be used to initialize the block of
> memory to all-bits-zero, but that's not necessarily as useful as you
> might expect.  There's no guarantee in the language that setting a
> floating-point or pointer object to all-bits-zero will set it to 0.0 or
> NULL, respectively (though it very commonly will).

The code in question only uses integers, so I didn't think it worthwhile
to bring up that issue.

[toc] | [prev] | [next] | [standalone]


#43022

FromKeith Thompson <kst-u@mib.org>
Date2014-04-16 10:38 -0700
Message-ID<lneh0x6upv.fsf@nuthaus.mib.org>
In reply to#43019
James Kuyper <jameskuyper@verizon.net> writes:
> On 04/16/2014 12:07 PM, Keith Thompson wrote:
> ...
>> Either calloc() or memset() can be used to initialize the block of
>> memory to all-bits-zero, but that's not necessarily as useful as you
>> might expect.  There's no guarantee in the language that setting a
>> floating-point or pointer object to all-bits-zero will set it to 0.0 or
>> NULL, respectively (though it very commonly will).
>
> The code in question only uses integers, so I didn't think it worthwhile
> to bring up that issue.

In that case you're right.  (I didn't take the time to read the code.)

Then again, the code could change, and/or it might be useful to someone
else.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#43023

FromKaz Kylheku <kaz@kylheku.com>
Date2014-04-16 19:37 +0000
Message-ID<20140416123642.507@kylheku.com>
In reply to#43022
On 2014-04-16, Keith Thompson <kst-u@mib.org> wrote:
> James Kuyper <jameskuyper@verizon.net> writes:
>> On 04/16/2014 12:07 PM, Keith Thompson wrote:
>> ...
>>> Either calloc() or memset() can be used to initialize the block of
>>> memory to all-bits-zero, but that's not necessarily as useful as you
>>> might expect.  There's no guarantee in the language that setting a
>>> floating-point or pointer object to all-bits-zero will set it to 0.0 or
>>> NULL, respectively (though it very commonly will).
>>
>> The code in question only uses integers, so I didn't think it worthwhile
>> to bring up that issue.
>
> In that case you're right.  (I didn't take the time to read the code.)
>
> Then again, the code could change, and/or it might be useful to someone
> else.

Yes, somenoe else hacking away in the basement of the Smithsonian on some
machine with not-all-zero-bits null pointers, funded by a "cultural grant",
rather than actual customers or investors.

[toc] | [prev] | [next] | [standalone]


#43034

FromUdyant Wig <udyantw@gmail.com>
Date2014-04-17 12:00 +0530
Message-ID<87vbu8a2n8.fsf@panda.goosenet.in>
In reply to#43017
Keith Thompson <kst-u@mib.org> writes:
| Either calloc() or memset() can be used to initialize the block of
| memory to all-bits-zero, but that's not necessarily as useful as you
| might expect.  There's no guarantee in the language that setting a
| floating-point or pointer object to all-bits-zero will set it to 0.0 or
| NULL, respectively (though it very commonly will).

 I see now that this is indeed mentioned in the discussion regarding
 calloc() on page 408 of the 5th edition of Harbison and Steele:

    Note that memory cleared bitwise to zero might not have the same
    representation as a floating-point zero or a null pointer.
 
| If you don't mind making your code a bit non-portable (and in fact
| systems where 0.0 and NULL *aren't* represented as all-bits-zero are
| rare), then calloc() or memset() can be reasonable.  It will at least
| make the initial contents of the allocated memory consistent, even if
| it's not necessarily correct.

 As I did not use floats or doubles, I suppose the program is safe.
 
| An alternative is to carefully write your code so that it never accesses
| memory before it's been explicitly initialized to some meaningful value.
| (Valgrind can help with that.)

 I shall keep that in mind as an alternate strategy when memory cannot
 be initialized for some reason.

 Running my program through Valgrind now reports no errors.

[toc] | [prev] | [next] | [standalone]


#43036

Fromglen herrmannsfeldt <gah@ugcs.caltech.edu>
Date2014-04-17 09:32 +0000
Message-ID<lio73c$umb$1@speranza.aioe.org>
In reply to#43034
Udyant Wig <udyantw@gmail.com> wrote:

(snip, someone wrote)
> | If you don't mind making your code a bit non-portable (and in fact
> | systems where 0.0 and NULL *aren't* represented as all-bits-zero are
> | rare), then calloc() or memset() can be reasonable.  It will at least
> | make the initial contents of the allocated memory consistent, even if
> | it's not necessarily correct.
 
> As I did not use floats or doubles, I suppose the program is safe.

Is there a processor built in the last 50 years that doesn't use
all bits zero for floating point zero?

Using a biased exponent, an exponent of zero bits is the smallest
exponent, which a zero should have. 

From Blaauw and Brooks "Computer Architecture: Concepts and Evolution"

there are processors with sign magnitude, ones complement, or
twos complement exponents, Some such machines are the IBM 1620,
Ferranti Atlas, CDC 6600, Burroughs B5500, and the CDC STAR-100.

Even so, they could special case zero, which I believe some of
those do. I believe you will only find them running in a museum.

-- glen

[toc] | [prev] | [next] | [standalone]


#43037

From"BartC" <bc@freeuk.com>
Date2014-04-17 12:24 +0100
Message-ID<QRO3v.16209$5V5.7003@fx08.am4>
In reply to#43036

"glen herrmannsfeldt" <gah@ugcs.caltech.edu> wrote in message
news:lio73c$umb$1@speranza.aioe.org...
> Udyant Wig <udyantw@gmail.com> wrote:
>
> (snip, someone wrote)
>> | If you don't mind making your code a bit non-portable (and in fact
>> | systems where 0.0 and NULL *aren't* represented as all-bits-zero are
>> | rare), then calloc() or memset() can be reasonable.  It will at least
>> | make the initial contents of the allocated memory consistent, even if
>> | it's not necessarily correct.
>
>> As I did not use floats or doubles, I suppose the program is safe.
>
> Is there a processor built in the last 50 years that doesn't use
> all bits zero for floating point zero?
>
> Using a biased exponent, an exponent of zero bits is the smallest
> exponent, which a zero should have.
>
> From Blaauw and Brooks "Computer Architecture: Concepts and Evolution"
>
> there are processors with sign magnitude, ones complement, or
> twos complement exponents, Some such machines are the IBM 1620,
> Ferranti Atlas, CDC 6600, Burroughs B5500, and the CDC STAR-100.
>
> Even so, they could special case zero, which I believe some of
> those do. I believe you will only find them running in a museum.

That's easy enough to test for. Just put a range of checks at the start of
an application, which determine whether in fact 0.0 floats or doubles, and
null pointers, are all-bits-zero, if this is the assumption made in the rest
of program.

Then it can simply abort on any rogue machine (and maybe you can then decide
to deal with that if you think it's worthwhile).

Otherwise no point crippling the software on every other machine just in
case.

-- 
Bartc 

[toc] | [prev] | [next] | [standalone]


#43042

FromKeith Thompson <kst-u@mib.org>
Date2014-04-17 08:16 -0700
Message-ID<ln61m86l68.fsf@nuthaus.mib.org>
In reply to#43037
"BartC" <bc@freeuk.com> writes:
> "glen herrmannsfeldt" <gah@ugcs.caltech.edu> wrote in message
> news:lio73c$umb$1@speranza.aioe.org...
[...]
>> Is there a processor built in the last 50 years that doesn't use
>> all bits zero for floating point zero?
[...]
> That's easy enough to test for. Just put a range of checks at the start of
> an application, which determine whether in fact 0.0 floats or doubles, and
> null pointers, are all-bits-zero, if this is the assumption made in the rest
> of program.
>
> Then it can simply abort on any rogue machine (and maybe you can then decide
> to deal with that if you think it's worthwhile).

In principle, that could fail if all-bits-zero is a trap
representation for floating-point or pointer types.  For that matter,
it's conceivable that all-bits-zero could be a representation of
0.0 for some floating-point types but not for others; likewise for
pointer types.

Another problem is that if you write such checks, you have code in your
application that will never be executed (unless you somehow manage to
run it on an exotic system with non-zero representations for 0.0 and/or
NULL).  If you get the checking code wrong, you might never know.

It might be better just to document the assumption in a comment.

> Otherwise no point crippling the software on every other machine just in
> case.

Crippling?  I haven't found it particularly difficult to write code
that doesn't *care* whether all-bits-zero is a valid representation
for 0.0 or NULL.  Sure, it's sometimes convenient to be able to use
memset() to clear an array or structure that might contain data
of arbitrary types, but a { 0 } initializer will do the same thing
more portably.

I don't advocate going (very far) out of your way to allow for the
possibility that your code might run on some exotic, and perhaps
nonexistent, architecture.  What I do advocate is being aware of
the issues, and understanding the distinction between the guarantees
made by the C standard and the somewhat larger set of things you can
(reasonably) safely assume.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#43038

FromMalcolm McLean <malcolm.mclean5@btinternet.com>
Date2014-04-17 04:41 -0700
Message-ID<42d378bd-3e5f-4dcc-a482-ce0acfe77ce1@googlegroups.com>
In reply to#43036
On Thursday, April 17, 2014 10:32:28 AM UTC+1, glen herrmannsfeldt wrote:
> Udyant Wig <udyantw@gmail.com> wrote:
> 
> Is there a processor built in the last 50 years that doesn't use
> all bits zero for floating point zero?
> 
People still produce processors without floating point units, not normally for general-purpose
computers, but for small embedded applications.
C floating point arithmetic is then implemented in a quick and dirty way, often by having one
byte of sign/exponent and two of mantissa. Probably most still use biased exponents, but a few
might use a signed exponent with -128 coded to zero. I don't actually know of any examples.

[toc] | [prev] | [next] | [standalone]


#43039

FromLes Cargill <lcargill99@comcast.com>
Date2014-04-17 07:49 -0500
Message-ID<lioibv$q3f$1@dont-email.me>
In reply to#43038
Malcolm McLean wrote:
> On Thursday, April 17, 2014 10:32:28 AM UTC+1, glen herrmannsfeldt wrote:
>> Udyant Wig <udyantw@gmail.com> wrote:
>>
>> Is there a processor built in the last 50 years that doesn't use
>> all bits zero for floating point zero?
>>
> People still produce processors without floating point units, not normally for general-purpose
> computers, but for small embedded applications.
> C floating point arithmetic is then implemented in a quick and dirty way, often by having one
> byte of sign/exponent and two of mantissa. Probably most still use biased exponents, but a few
> might use a signed exponent with -128 coded to zero. I don't actually know of any examples.
>

I am always willing to be proven wrong, but I don't think strong
portability will be of that much value in those cases.

-- 
Les Cargill

[toc] | [prev] | [next] | [standalone]


#43040

FromKeith Thompson <kst-u@mib.org>
Date2014-04-17 08:00 -0700
Message-ID<lna9bk6lxm.fsf@nuthaus.mib.org>
In reply to#43034
Udyant Wig <udyantw@gmail.com> writes:
> Keith Thompson <kst-u@mib.org> writes:
[...]
> | If you don't mind making your code a bit non-portable (and in fact
> | systems where 0.0 and NULL *aren't* represented as all-bits-zero are
> | rare), then calloc() or memset() can be reasonable.  It will at least
> | make the initial contents of the allocated memory consistent, even if
> | it's not necessarily correct.
>
>  As I did not use floats or doubles, I suppose the program is safe.

It should be (at least as far as that's concerned).  The standard
guarantees that all-bits-zero is a representation of 0 for any
integer type.

(Interestingly, this was not guaranteed by the C90 or C99 standard.
It was added to one of the C99 Technical Corrigenda, presumably
because *all* implementations already work that way.)

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


Page 1 of 5  [1] 2 3 4 5  Next page →

Back to top | Article view | comp.lang.c


csiph-web