<?xml version="1.0" encoding="UTF-8"?> <rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
> <channel><title>ProgramError &#187; Computer Science</title> <atom:link href="http://programerror.com/category/computer-science/feed/" rel="self" type="application/rss+xml" /><link>http://programerror.com</link> <description>The Works of David Michael Bryson</description> <lastBuildDate>Wed, 29 Jun 2011 16:19:41 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3.1</generator> <atom:link rel="next" href="http://programerror.com/category/computer-science/feed/?page=2" /> <item><title>TestRunner 2.0 now available</title><link>http://programerror.com/2011/05/testrunner-2-0-now-available/</link> <comments>http://programerror.com/2011/05/testrunner-2-0-now-available/#comments</comments> <pubDate>Fri, 06 May 2011 16:37:58 +0000</pubDate> <dc:creator>David</dc:creator> <category><![CDATA[Computer Science]]></category> <category><![CDATA[TestRunner]]></category> <guid
isPermaLink="false">http://programerror.com/?p=387</guid> <description><![CDATA[I have just posted TestRunner 2.0. New features include Git support and JUnit compatible XML report generation. See the TestRunner page for more details. TestRunner itself is now managed with Git as well. You may clone the master repository at &#8230; <a
href="http://programerror.com/2011/05/testrunner-2-0-now-available/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>I have just posted TestRunner 2.0.   New features include Git support and JUnit compatible XML report generation.  See the <a
href="http://programerror.com/software/testrunner">TestRunner</a> page for more details.</p><p>TestRunner itself is now managed with Git as well.  You may clone the master repository at <a
href="git://programerror.com/testrunner.git">git://programerror.com/testrunner.git</a>, or fork the mirror at <a
href="http://github.com/brysonda/testrunner">GitHub</a>.</p> ]]></content:encoded> <wfw:commentRss>http://programerror.com/2011/05/testrunner-2-0-now-available/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Centering custom views inside an NSScrollView</title><link>http://programerror.com/2011/04/centering-custom-views-inside-an-nsscrollview/</link> <comments>http://programerror.com/2011/04/centering-custom-views-inside-an-nsscrollview/#comments</comments> <pubDate>Mon, 25 Apr 2011 16:02:08 +0000</pubDate> <dc:creator>David</dc:creator> <category><![CDATA[Computer Science]]></category> <category><![CDATA[Avida]]></category> <category><![CDATA[Cocoa]]></category> <category><![CDATA[NSClipView]]></category> <category><![CDATA[NSScrollView]]></category> <guid
isPermaLink="false">http://programerror.com/?p=370</guid> <description><![CDATA[In Cocoa, a NSScrollView provides basic functionality for encapsulating a view with a scrolling frame. It provides the appropriate plumbing and hooks it all together so that it &#8216;just works&#8217;. At least in theory. In practice, I encountered a few &#8230; <a
href="http://programerror.com/2011/04/centering-custom-views-inside-an-nsscrollview/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>In Cocoa, a NSScrollView provides basic functionality for encapsulating a view with a scrolling frame.   It provides the appropriate plumbing and hooks it all together so that it &#8216;just works&#8217;.  At least in theory.  In practice, I encountered a few gaps in functionality and documentation when enclosing my own custom view inside an NSScrollView.   These gaps may simply be due to my own limited experience with Cocoa so far, but nonetheless the following bits may be helpful to others with similar challenges.</p><h2>Setting View Size</h2><p>NSScrollViews will automatically adjust scroll bar positions and sizes to the accommodate the document view that they encapsulate.  This behavior is controlled by monitoring the <em>frame</em> size of the content NSView-subclass instance.  Whenever the desired size of the document changes, simply set the frame size appropriately:</p><pre class="subtopic">
NSSize desiredSize;
desiredSize.width = 500.0;
desiredSize.height = 500.0;
[theDocumentView setFrameSize:desiredSize];
</pre><h2>Centering the Document</h2><p>This bit is somewhat more complicated.  The default behavior of NSScrollView revolves around document views with layout that flows from the origin, bottom left by default.   Whenever the content view is smaller the scroll view, the position is locked to the origin.  In my case, however, I want the enclosed view to be centered whenever it is small enough to fit.  There is no means to do this out of the box, though.</p><p>The general consensus of forums and mailing lists seems to be that this is best accomplished by subclassing NSClipView and replacing the <em>content view</em> of the scroll view with this subclass.   The basic idea is to catch frame size changes and trigger the centering behavior under appropriate conditions.  The following interface comes from my implementation of such a clip view subclass in <a
href="http://avida.devosoft.org/viewer-macos">Avida : Mac OS Viewer</a> (BSD-style license):</p><pre class="subtopic">
@interface CenteringClipView : NSClipView {
  NSPoint viewPoint;
}
- (id) initWithFrame:(NSRect)frame;
- (void) centerView;
// NSClipView Method Overrides
- (NSPoint) constrainScrollPoint:(NSPoint)proposedNewOrigin;
- (void) viewBoundsChanged:(NSNotification*)notification;
- (void) viewFrameChanged:(NSNotification*)notification;
- (void) setFrame:(NSRect)frameRect;
- (void) setFrameOrigin:(NSPoint)newOrigin;
- (void) setFrameSize:(NSSize)newSize;
- (void) setFrameRotation:(CGFloat)angle;
@end
</pre><p>The implementation consists of two core methods that handle most of the work, <em>centerView</em> and <em>constrainScrollPoint:(NSPoint)</em>. The <em>centerView</em> method finds the appropriate origin point for the clipping rect given the size of the document.  When the document is small enough to fit, the origin will center the document.  When the document is larger than the scroll view, it will adjust the origin relative to the last scroll point of the view.  The <em>constrainScrollPoint:(NSPoint)</em> method is a core NSClipView method that may be used to constrain scrolling behavior in subclasses.   In CenteringClipView, the method keeps the scroll point fixed in any direction that is smaller than the scroll view size, otherwise bounding scrolling within the document.  It also stashes the current scroll point in <em>self.viewPoint</em> for use in <em>centerView</em>.</p><pre class="subtopic">
- (void) centerView {
  NSRect docRect = [[self documentView] frame];
  NSRect clipRect = [self bounds];
  // Center the clipping rect origin x
  if (docRect.size.width < clipRect.size.width) {
    clipRect.origin.x = roundf((docRect.size.width - clipRect.size.width) / 2.0);
  } else {
    clipRect.origin.x = roundf(viewPoint.x * docRect.size.width - (clipRect.size.width / 2.0));
  }
  // Center the clipping rect origin y
  if (docRect.size.height < clipRect.size.height) {
    clipRect.origin.y = roundf((docRect.size.height - clipRect.size.height) / 2.0);
  } else {
    clipRect.origin.y = roundf(viewPoint.y * docRect.size.width - (clipRect.size.height / 2.0));
  }
  // Scroll the document to the selected center point
  NSScrollView* scrollView = (NSScrollView*)[self superview];
  [self scrollToPoint:[self constrainScrollPoint:clipRect.origin]];
  [scrollView reflectScrolledClipView:self];
}
- (NSPoint) constrainScrollPoint:(NSPoint)proposedNewOrigin {
  NSRect docRect = [[self documentView] frame];
  NSRect clipRect = [self bounds];
  CGFloat maxX = docRect.size.width - clipRect.size.width;
  CGFloat maxY = docRect.size.height - clipRect.size.height;
  clipRect.origin = proposedNewOrigin;
  if (docRect.size.width < clipRect.size.width) {
    clipRect.origin.x = roundf(maxX / 2.0);
  } else {
    clipRect.origin.x = roundf(MAX(0, MIN(clipRect.origin.x, maxX)));
  }
  if (docRect.size.height < clipRect.size.height) {
    clipRect.origin.y = roundf(maxY / 2.0);
  } else {
    clipRect.origin.y = roundf(MAX(0, MIN(clipRect.origin.y, maxY)));
  }
  viewPoint.x = NSMidX(clipRect) / docRect.size.width;
  viewPoint.y = NSMidY(clipRect) / docRect.size.height;
  return clipRect.origin;
}
</pre><p>The last bits of the implementation simply catch frame size changes.  The methods are forwarded to the superclass (NSClipView), then followed by a call to <em>centerView</em> ensuring that the document stays centered as desired.</p><pre class="subtopic">
- (void) viewBoundsChanged:(NSNotification*)notification {
  [super viewBoundsChanged:notification];
  [self centerView];
}
- (void) viewFrameChanged:(NSNotification*)notification {
  [super viewBoundsChanged:notification];
  [self centerView];
}
- (void) setFrame:(NSRect)frameRect {
  [super setFrame:frameRect];
  [self centerView];
}
- (void) setFrameOrigin:(NSPoint)newOrigin {
  [super setFrameOrigin:newOrigin];
  [self centerView];
}
- (void) setFrameSize:(NSSize)newSize {
  [super setFrameSize:newSize];
  [self centerView];
}
- (void) setFrameRotation:(CGFloat)angle {
  [super setFrameRotation:angle];
  [self centerView];
}
</pre><p>Once you have a clip view that handles the behavior you want, you need to set it up for use in your scroll view.   Unfortunately, this cannot be done through Interface Builder.  Rather, you will need a few lines in your initialization code for the view.  In my case, I used the <em>windowDidLoad</em> method of my window controller, so that I can be sure that the view has been loaded fully.</p><pre class="subtopic">
- (void) windowDidLoad {
  ...
  // Replace NSClipView of scrollView with a CenteringClipView
  id docView = [scrollView documentView];
  NSClipView* clipView = [[CenteringClipView alloc] initWithFrame:[docView frame]];
  [scrollView setContentView:clipView];
  [scrollView setDocumentView:docView];
  ...
}
</pre><h2>Strange Document Frame Origin Behavior</h2><p>If you have implemented a custom clip view as described above, you may observe some strange behavior when resizing the enclosing scroll view.  My document view would shift away from to origin, occasionally snapping back to the correct position. It may have been an result of my set original set up in Interface Builder, but the root cause appears to have been artifacts in automatic subview resizing.  The solution was to explicitly disable subview resizing in CenteringClipView.</p><pre class="subtopic">
- (id) initWithFrame:(NSRect)frame {
  self = [super initWithFrame:frame];
  if (self) {
    viewPoint = NSMakePoint(0, 0);
    [self setAutoresizesSubviews:NO];
  }
  return self;
}
</pre><h2>Handling Scroller Visibility</h2><p>If you want the scrollers of the scroll view to disappear when not in use, you should be able to set automatic scroller hiding on the NSScrollView class.  However, in my experience, the automatic behavior was not triggered properly by my clip view.  The prevailing solution to this appears to entail taking scroll bar handling into your own hands.   I disabled automatic scroll bar hiding and wrote my own code to do it.   I won't go into details here, but rather refer you to my implementation in <a
href="http://avida.devosoft.org/viewer-macos/">Avida : Mac OS Viewer's</a> CenteringClipView class for details.</p><h2>Conclusion</h2><p>These tidbits are, of course, not intended to be a detailed tutorial for using NSScrollViews.   However, since it took quite a bit of search, debugging, and head scratching to solve them, I thought it be worth jotting them down.  Hopefully they will make it into Google and be useful for others new to Cocoa.   If you are more familiar with Cocoa, please let me know if there is a better way to do any of the above.</p> ]]></content:encoded> <wfw:commentRss>http://programerror.com/2011/04/centering-custom-views-inside-an-nsscrollview/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Iterative calculation of lies, er stats</title><link>http://programerror.com/2009/10/iterative-calculation-of-lies-er-stats/</link> <comments>http://programerror.com/2009/10/iterative-calculation-of-lies-er-stats/#comments</comments> <pubDate>Thu, 22 Oct 2009 15:49:12 +0000</pubDate> <dc:creator>David</dc:creator> <category><![CDATA[Computer Science]]></category> <guid
isPermaLink="false">http://programerror.com/?p=122</guid> <description><![CDATA[A few weeks ago I wrote about my adventures in cross platform floating point consistency in Avida. The main routine responsible for the deviation at the time was a statistics output function that calculated the skewness and kurtosis for various &#8230; <a
href="http://programerror.com/2009/10/iterative-calculation-of-lies-er-stats/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>A few weeks ago I wrote about my adventures in cross platform floating point consistency in Avida.  The main routine responsible for the deviation at the time was a statistics output function that calculated the skewness and kurtosis for various properties.  My first thought at the time was that perhaps the compilers were reordering operations differently, leading to rounding variations.   Ultimately I worked around the problem (see <a
href="http://programerror.com/2009/09/when-gccs-ffast-math-isnt/">how</a>), but in the process I took a good long look skewness and kurtosis methods.</p><p>The class in question, <code>cDoubleSum</code>, is intended to be a lightweight iterative/running statistics utility.  Values can be added to the collection as they are observed and the statistical properties, such as variance, skewness, and kurtosis, are updated accordingly.  The implementation does this by keeping a running tally of the sum, sum of squared values, sum of cubed values, and the sum of x^4.  The values are then used to calculate the desired values.</p><pre class="subtopic">
void Add(double value, double weight = 1.0)
{
  double w_val = value * weight;
  n += weight;
  s1 += w_val;
  s2 += w_val * w_val;
  s3 += w_val * w_val * w_val;
  s4 += w_val * w_val * w_val * w_val;
}
</pre><p>The skewness and kurtosis methods are implemented as the following:</p><pre class="subtopic">
double cDoubleSum::Skewness() const
{
  return (n > 2.0) ?
    (n * s3 - (3.0 * s2) * s1 + ((2.0 * s1) * s1) * s1 / n) /
      ((n - 1.0) * (n - 2.0))
    : INF_ERR;
}
double cDoubleSum::Kurtosis() const {
  return (n > 3.0) ?
    (n + 1.0) * (n * s4 - (4.0 * s3) * s1 + (((6.0 * s2) * s1) * s1) /
      n - (((((3.0 * s1) * s1) * s1) / n) * s1) / n) /
      ((n - 1.0) * (n - 2.0) * (n - 3.0))
    : INF_ERR;
}
</pre><p>Since the code has existed for quite a few years, its exact lineage is unknown.  I have done extensive searching to try to understand how these equations work and to find where they came from.  In asking around it was suggested that the source might have been &#8220;Numerical Recipes in C&#8221;.  However, the book only describes the basic two pass method that requires all values exist in memory during calculation.  Even worse, the equations used by <code>cDoubleSum</code> do not seem to calculate correct values.</p><p>After starring at the code and many versions of the equations, I decided it would be better to go ahead and implement my own version of the class.   The result was <code>cRunningStats</code>.</p><pre class="subtopic">
class cRunningStats
{
private:
  double m_n;  // count
  double m_m1; // mean
  double m_m2; // second moment
  double m_m3; // third moment
  double m_m4; // fourth moment
public:
  cRunningStats() : m_n(0.0), m_m1(0.0), m_m2(0.0), m_m3(0.0), m_m4(0.0)
    { ; }
  void Push(double x)
  {
    m_n++;
    double d = (x - m_m1);
    double d_n = d / m_n;
    double d_n2 = d_n * d_n;
    m_m4 += d * d_n2 * d_n * ((m_n - 1) * ((m_n * m_n) - 3 * m_n + 3)) +
            6 * d_n2 * m_m2 - 4 * d_n * m_m3;
    m_m3 += d * d_n2 * ((m_n - 1) * (m_n - 2)) - 3 * d_n * m_m2;
    m_m2 += d * d_n * (m_n - 1);
    m_m1 += d_n;
  }
  double Mean() { return m_m1; }
  double StdDeviation() { return sqrt(Variance()); }
  double StdError() { return (m_n > 1.0) ? sqrt(Variance() / m_n) : 0.0; }
  double Variance() { return (m_n > 1.0) ? (m_m2 / (m_n - 1.0)) : 0.0; }
  double Skewness() { return sqrt(m_n) * m_m3 / pow(m_m2, 1.5); }
  double Kurtosis() { return m_n * m_m4 / (m_m2 * m_m2); }
};
</pre><p>I have examined various primary sources, however the wikipedia page &quot;<a
href="http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance">Algorithms for calculating variance</a>&quot; is a good starting place if you are interested in where the math comes from.   The methods used should be numerically stable (i.e. not prone to severe loss of precision), reasonably high performance (only a single divide operation during update), and, best of all, return correct values.   There are a number of good pages on the web that describe pieces of this problem, including some that provide details for how such equations can be used to parallelize variance calculation.   Still, I thought it would be useful to have a nice concise presentation in C++ code.  Note that there are a few more methods, <code>inline</code>, and <code>const</code> qualifiers in the actual Avida implementation, but the math is the same.</p><p>A quick performance comparison has <code>cRunningStats</code> taking about 20% more time on a set of 100M random numbers versus <code>cDoubleSum</code> (same random number seed).  The value correctness tradeoff is, of course, well worth the cost.   However, if anyway knows how to make the cDoubleSum methods work correctly, I&#8217;d love to know the answer.  As things stand now, I have simply removed the bad code.</p><div
class="warn"> <em>License Note:</em> Feel free to use cRunningStats code as public domain.  An in source code attribution comment with a referral URL would be nice, but is not required.  The full class is available in Avida, licensed under the GPL.</div> ]]></content:encoded> <wfw:commentRss>http://programerror.com/2009/10/iterative-calculation-of-lies-er-stats/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>When GCC&#8217;s &#8220;-ffast-math&#8221; isn&#8217;t</title><link>http://programerror.com/2009/09/when-gccs-ffast-math-isnt/</link> <comments>http://programerror.com/2009/09/when-gccs-ffast-math-isnt/#comments</comments> <pubDate>Fri, 25 Sep 2009 17:12:37 +0000</pubDate> <dc:creator>David</dc:creator> <category><![CDATA[Avida]]></category> <category><![CDATA[Computer Science]]></category> <category><![CDATA[compilers]]></category> <category><![CDATA[optimization]]></category> <guid
isPermaLink="false">http://programerror.com/?p=89</guid> <description><![CDATA[Performance optimization is often about trade-offs, especially when you get into the implementation details of a program. A routine may go faster if you unroll loops to reduce branching overhead, however program code size increases as a result. If you &#8230; <a
href="http://programerror.com/2009/09/when-gccs-ffast-math-isnt/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>Performance optimization is often about trade-offs, especially when you get into the implementation details of a program.  A routine may go faster if you unroll loops to reduce branching overhead, however program code size increases as a result.  If you unroll too much you risk exceeding optimal cache sizes and end up with a slower program anyway.   Compilers are becoming increasingly capable of evaluating such tradeoffs, leaving the developer to the task of designing higher-level functionality.</p><p>GCC has long provided a compiler option &#8220;-ffast-math&#8221; that allows the compiler to use faster hardware floating point instructions, at the potential expense of IEEE floating point compliance.  If your program doesn&#8217;t need strict compliance, this setting should theoretically net a boost in floating point performance for <em>free</em>.</p><p>Avida is a very integer based program.  Floating point math is inherently imprecise and difficult to keep consistent across platforms.  As such, we have purposely kept floating point math isolated to the fringes as much as possible.  Still, as as scientific program we need to gather and calculate statistics, thus there are some commonly executed floating point routines.  The trade-off of a little accuracy for a boost in performance seemed worthwhile, thus we have compiled Avida with &#8216;fast-math&#8217; enabled for as long as I have been involved with the project, and likely since the beginning.</p><p>In recent years I built a consistency test framework that we have been slowly fleshing out with tests to keep Avida as consistent across platforms as possible.   Perhaps surprisingly, outside of a few notable exceptions, we haven&#8217;t experienced a lot of variance in output consistency.   One of the notable exceptions, though, has been compiling Avida with Intel&#8217;s ICC suite.   One of the stats routines was returning some floating point values with small variance relative GCC on all other platforms.</p><p>In my quest to bring ICC into consistency, I did some digging into the floating point settings.  ICC by default uses a &#8216;fast-math&#8217; like mode.  However, it clearly was using a variation in floating point instructions generated compared to GCC.   My first thought was that the optimizers may been exploiting commutativity to reorder operations, which could potentially affect rounding order.   After a bit of failed parenthesis wrangling I decided to test if full IEEE compliance would fix the variance and then try relaxing things.  So my next step was to disable &#8216;fast-math&#8217; on GCC.  This action alone changed the results to match ICC.   So the Intel compiler was actually generating more <em>correct</em> results.  Interesting.</p><p>Conventional wisdom says that &#8216;fast-math&#8217; should be, well, faster.  In order to get consistency though, it may no longer be worth the trade-off.   So I tested performance to see how much slower Avida would be, given the isolated nature of floating point operations.</p><div
class="subtopic"> <code>tatooine:development brysonda$ ./run_tests -j 8 -p<br
/> # results truncated for brevity<br
/> analyze_truncate_lineage_fulllandscape : exceeded<br
/> - wall: 0.92  base = 4.8564  test = 4.4588<br
/> - user: 0.92  base = 9.3931  test = 8.6456</code></div><p>Wait a minute&#8230;   its <em>faster</em>?</p><p>Disabling &#8216;fast-math&#8217; not only solved the consistency problem, it made Avida faster in certain cases and had no effect in others.   As seen above, it made as much as an 8% improvement on a first generation 8-core Mac Pro.  Further tests on my Power Mac G5 Quad showed around 2% improvement in some tests and no difference in others.</p><p>In the end I decided to disable &#8216;fast-math&#8217; for GCC and explicitly set full IEEE compliance mode on ICC, just to be sure.   Performance testing showed that no performance was lost, yet we now have full cross platform consistency between ICC and GCC.   Win win!</p><p>The take-away message is that it can be good to question conventional wisdom.  Also, just because it says &#8220;fast&#8221; in the name, it may not necessarily be true in all cases.</p> ]]></content:encoded> <wfw:commentRss>http://programerror.com/2009/09/when-gccs-ffast-math-isnt/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> </channel> </rss>
