[sf-perl] Farmer Puzzle

David Christensen dpchrist at holgerdanske.com
Wed Aug 26 00:50:28 PDT 2026


On 8/25/26 22:41, Shlomi Fish wrote:
> Hi David,


Hi, Shlomi.  Thank you for your insights.


> "my $a" and "my $b" are discouraged:
> https://perl-begin.org/tutorials/bad-elements/#vars-a-and-b


Thank you for the warning.  It has been a while since I fell into that 
trap.  Avoiding lexical $a and $b sounds like a good habit.


Is there a way for an inner scope/block to undeclare/forget lexical 
variables declared in an enclosing scope/block?


> On a different note: why aren't you working fully with integers? Products of
> cents or 50 cents.


The program uses floating point numbers because the problem statement 
gave animal prices in dollars.


Adding "use integer" and doing the monetary math in cents both improves 
performance and prevents floating point representation errors:

2026-08-26 00:36:26 dpchrist at laalaa ~/sandbox/perl/farmer-puzzle
$ expand dpchrist-integer-benchmark
#!/usr/bin/env perl
# $Id: dpchrist-integer-benchmark,v 1.2 2026/08/26 07:32:32 dpchrist Exp $
#
# A farmer goes to the fair.  Cows cost $10.00 each, pigs cost $3.00
# each, and sheep cost $0.50 each.  If the farmer wants to buy
# at least one cow, at least one pig, at least one sheep, and exactly
# 100 animals total, and wants to spend exactly $100.00, how many cows,
# pigs, and sheep should the farmer buy?  Find all solutions.
#
# Perl program by David Paul Christensen <dpchrist at holgerdanske.com>
#
# Public Domain

use strict;
use warnings;

use integer;

use constant animals            => 100;

use constant cow_cost           =>  1000;
use constant pig_cost           =>   300;
use constant sheep_cost         =>    50;
use constant budget             => 10000;

sub buy_fair_animals
{
     my @r;
     my $max_cows = (budget - pig_cost - sheep_cost)/cow_cost;
     foreach my $c (1 .. $max_cows) {
         my $max_pigs = (budget - $c * cow_cost - sheep_cost)
                        / pig_cost;
         foreach my $p (1 .. $max_pigs) {
             my $s = (budget - $c * cow_cost - $p * pig_cost)
                     / sheep_cost;
             my $total_animals = $c + $p + $s;
             last if $total_animals  > animals;
             next if $total_animals != animals;
             my $total_cost = $c * cow_cost
                              + $p * pig_cost
                              + $s * sheep_cost;
             last if $total_cost  > budget;
             next if $total_cost != budget;
             push @r, [$c, $p, $s];
         }
     }
     return @r;
}

my $n = @ARGV ? shift : 100_000;
buy_fair_animals() for 1 .. $n - 1;

my @r = buy_fair_animals();
foreach (@r) {
     my ($c, $p, $s) = @$_;
     my $total_animals = $c + $p + $s;
     my $total_cost = ($c * cow_cost + $p * pig_cost + $s * sheep_cost)
                      / 100;
     print "cows $c pigs $p sheep $s " .
            "animals $total_animals cost $total_cost\n";
}

2026-08-26 00:36:34 dpchrist at laalaa ~/sandbox/perl/farmer-puzzle
$ time perl dpchrist-integer-benchmark
cows 5 pigs 1 sheep 94 animals 100 cost 100

real	0m0.957s
user	0m0.953s
sys	0m0.004s

2026-08-26 00:36:42 dpchrist at laalaa ~/sandbox/perl/farmer-puzzle
$ time perl dpchrist-integer-benchmark
cows 5 pigs 1 sheep 94 animals 100 cost 100

real	0m0.941s
user	0m0.937s
sys	0m0.004s

2026-08-26 00:36:43 dpchrist at laalaa ~/sandbox/perl/farmer-puzzle
$ time perl dpchrist-integer-benchmark
cows 5 pigs 1 sheep 94 animals 100 cost 100

real	0m0.978s
user	0m0.974s
sys	0m0.004s


But, integer variables impose a cost upon the programmer --I must 
understand the minutia of every calculation to keep the term and 
expression values within the range of integers.


Unfortunately, "use bigint" is not a good solution -- 100_000/200 = 500 
times slower:

2026-08-26 00:42:58 dpchrist at laalaa ~/sandbox/perl/farmer-puzzle
$ time perl dpchrist-bigint-benchmark 200
cows 5 pigs 1 sheep 94 animals 100 cost 100

real	0m0.948s
user	0m0.947s
sys	0m0.001s

2026-08-26 00:43:02 dpchrist at laalaa ~/sandbox/perl/farmer-puzzle
$ time perl dpchrist-bigint-benchmark 200
cows 5 pigs 1 sheep 94 animals 100 cost 100

real	0m0.969s
user	0m0.960s
sys	0m0.009s

2026-08-26 00:43:06 dpchrist at laalaa ~/sandbox/perl/farmer-puzzle
$ time perl dpchrist-bigint-benchmark 200
cows 5 pigs 1 sheep 94 animals 100 cost 100

real	0m0.974s
user	0m0.970s
sys	0m0.005s


David



More information about the SanFrancisco-pm mailing list