Alistair Maclean's Web Site
The Code For
The Calculator
Back

What this code attempts to do is:

  • allow input of a limited series of characters
  • allow input of operations
  • convert the character strings to numbers
  • apply the operations
  • convert the numbers back to character strings
  • output the result
All the activity takes place on the server, this is PHP code, not Javascript.

The conversion of the Roman numbers back and forth was slightly messy, and the conversion from Roman to decimal may still be a bit fraught (there are so many possible illegal combinations). To add spice to the whole thing, this is about the third go round on the operations state machine, I still think it may need some work. However, that said, the calculator seems to function. I still have found no specific use for it other than the curiosity value.

The most recent shinanigans required a minor change to the way the code handles sessions. PHP 4.2.x changed the old session handling and now the session values, those carried between invocations are placed into explicit session handled space, not just left to the whim of the server.

A.M. Nov 9th 2002

More changes, this time because I have changed to a php that does not do register_globals. (Not reflected in listing below.)

A.M. Dec 10th 2005


<?php 
	/* ************************************************************************************************* */
	/* ************************************************************************************************* */
	/* ************************************************************************************************* */
	/* ************************************************************************************************* */

	class romancalculator
	{
		function romancalculator()
		{
			$this->mode = -1;
			$this->lastmode = -1;
			$this->rollingvalue = 0;
		}
		
		function ToRoman($MyNumber)
		{
			$m = $MyNumber;
			$romanstr = "";
			while ($m >= 1000)
			{
				$romanstr .= "M";
				$m -= 1000;
			}
			if ($m >= 900)
			{
				$romanstr .= "CM";
				$m -= 900;
			}
			if ($m >= 500)
			{
				$romanstr .= "D";
				$m -= 500;
			}			
			if ($m >= 400)
			{
				$romanstr .= "CD";
				$m -= 400;
			}			
			while ($m >= 100)
			{
				$romanstr .= "C";
				$m -= 100;
			}			
			if ($m >= 90)
			{
				$romanstr .= "XC";
				$m -= 90;
			}
			if ($m >= 50)
			{
				$romanstr .= "L";
				$m -= 50;
			}			
			if ($m >= 40)
			{
				$romanstr .= "XL";
				$m -= 40;
			}			
			while ($m >= 10)
			{
				$romanstr .= "X";
				$m -= 10;
			}			
			if ($m >= 9)
			{
				$romanstr .= "IX";
				$m -= 9;
			}
			if ($m >= 5)
			{
				$romanstr .= "V";
				$m -= 5;
			}			
			if ($m == 4)
			{
				$romanstr .= "IV";
				$m -= 4;
			}			
			while ($m > 0)
			{
				$romanstr .= "I";
				$m -= 1;
			}			
			
			// echo "<p>".$romanstr."= ToRoman(".$MyNumber.")</p>";
			return $romanstr;
		}
	
		function NumeralToNumber($numeral)
		{
			// $retval = 0;
			switch ($numeral)
			{
				case 'I' : return 1; break;
				case 'V' : return 5; break;
				case 'X' : return 10; break;
				case 'L' : return 50; break;
				case 'C' : return 100; break;
				case 'D' : return 500; break;
				case 'M' : return 1000; break;
				default : return 0;
			}
			
			// echo "<p>".$retval."= NumeralToNumber(".$numeral.")</p>";
			// return $retval;
		}
	
		function ToDecimal($Str)
		{
			$romanstrlen = strlen($Str);
			// echo "<p>Found ".$romanstrlen." characters to process</p>";
			$lastvalue = 0;
			$totalvalue = 0;

			/* 
				Run through the string of numerals in reverse order
				if the current digit is greater or equal to the last, add it
				if the current digit is less than the last, subtract it
				This handles the CM, IX, pairs,
				I realise that you could get some illegal pairs here... IM, XM, etc
			*/			
			for ($ii = ($romanstrlen - 1) ; $ii >= 0; $ii--)
			{
				$number = $this->NumeralToNumber(substr($Str, $ii, 1));
				// echo "<p>Proccessed:".substr($Str, $ii, 1)." to get :".$number."</p>";
				if ($number < $lastvalue)
				{
					$totalvalue -= $number;
				}					
				else
				{
					$totalvalue += $number; 
				}

				$lastvalue = $number;
			} 
			// echo "<p>".$totalvalue."= ToDecimal(".$Str.")</p>";
			return $totalvalue;
		}

		var $mode;							// stores the current calculating mode (+ - * / )
		var $lastmode;						// stores the last calculating mode
		var $rollingvalue;					// stores the running total
		var $roman1;						// stores the string value being typed in
	}

	session_start();
	/* ************************************************************************************************* */
	/*	Roman Calculator in PHP																			 */
	/*	This code hopefully presents the operation of a roman numeral calculator						 */
	/*																									 */
	/*																									 */
	/*	History:																						 */
	/*		AM	11/09/2002	Altered to account for PHP 4.2.x differences in session handling			 */
	/*																									 */
	/*																									 */
	/*																									 */
	/* ************************************************************************************************* */

	/* ************************************************************************************************* */
	/* ************************************************************************************************* */
	/* ************************************************************************************************* */
	/* ************************************************************************************************* */

	// There should be a roman calculator object if we did this before
	if (isset($_SESSION['rc']))
	{
		$rc = $_SESSION['rc'];
		$calcvalue = $rc->roman1;
	}
	else
	{
		// If we have no pre-existing calculator object then we are
		// here for the first time, so create one 
		$rc = new romancalculator;
		$_SESSION['rc'] = $rc;
		$calcvalue = "";
	}

	
	// Add the input value to the current (ongoing) value string
	if (isset($I))
	{
		$rc->roman1 = $calcvalue."I";
		//echo "<p>value = I</p>";
	}
	else if (isset($V))
	{
		$rc->roman1 = $calcvalue."V";
		//echo "<p>value = V</p>";
	}
	else if (isset($X))
	{
		$rc->roman1 = $calcvalue."X";
		//echo "<p>value = X</p>";
	}
	else if (isset($L))
	{
		$rc->roman1 = $calcvalue."L";
		//echo "<p>value = L</p>";
	}
	else if (isset($D))
	{
		$rc->roman1 = $calcvalue."D";
		//echo "<p>value = D</p>";
	}
	else if (isset($C))
	{
		$rc->roman1 = $calcvalue."C";
		//echo "<p>value = C</p>";
	}
	else if (isset($M))
	{
		$rc->roman1 = $calcvalue."M";
		//echo "<p>value = M</p>";
	}
	else if (isset($clear))
	{
		// remove the last calc inputs
		$rc->roman1 = "";
		$rc->mode = $rc->lastmode;
	}
	else if (isset($reset))
	{
		// reset the entire calculating engine
		$rc->roman1 = "";
		$rc->rollingvalue = 0;
		$rc->mode = -1;
		$rc->lastmode = -1;
	}
	else 
	{
		// Do calc's 
		//	Act on last mode
		// 	Then set mode to whatever we need to 
		// 	If there is no data ignore input

		if ($rc->rollingvalue == 0 && trim($rc->roman1) == "")
		{
			// ignore
		}
		else
		{		
			if (! trim($rc->roman1) == "")
			{						
				// Now do a calc based on the current mode
				// do the calculation?
				switch ($rc->mode)
				{
				case 0: 
					// do an add
					$rc->rollingvalue += $rc->ToDecimal($rc->roman1);
					break;
				case 1:
					// do a minus
					$rc->rollingvalue -= $rc->ToDecimal($rc->roman1);
					break;
				case 2:
					// do a multiply
					$rc->rollingvalue *= $rc->ToDecimal($rc->roman1);
					break;
				case 3:
					// do a divide
					$rc->rollingvalue = round($rc->rollingvalue / $rc->ToDecimal($rc->roman1));
					break;
				case -1:
					// some sort of error 
					$rc->rollingvalue = $rc->ToDecimal($rc->roman1);
					break;
				default:
					break;
				}
				$rc->roman1 = "";
			}
		}			
		$rc->lastmode = $rc->mode;
		if (isset($plus))
		{
			$rc->mode = 0;
		}
		if (isset($minus))
		{
			$rc->mode = 1;
		}
		if (isset($multiply))
		{
			$rc->mode = 2;
		}
		if (isset($divide))
		{
			$rc->mode = 3;
		}
	}	

	/* ************************************************************************************************* */
	/* ************************************************************************************************* */
	/* ************************************************************************************************* */
	/* ************************************************************************************************* */

	// save the currect roman calc values
	$_SESSION['rc'] = $rc;

?>


<html>
<head>
	<title><^l<vl^tor</title>
	<meta http-equiv="Keywords" content="roman numerals calculator">
	<meta http-equiv="Description" content="Attempt to make a roman numeral calculator">
</head>

<body background="images/marble1.jpg">
	<h1 style="color:maroon">SPQR Calculator</h1>
	<p><a href="default.htm" border="0">Home Page</a></p>

	
	<!-- form border="1" action="romancalc_failing.php" method="post" -->
	<form border="1" action="romancalc.htm" method="post">
		<table width="300">
			<tr>
				<td>
					<font style="color:white;font-size:15pt">Enter</font>
				</td>
				<td>
					<font style="color:white;font-size:15pt">Result</font>
				</td>
			</tr>
			<tr>
				<td>
					<?
						if (isset($calcvalue))
						{
							echo "<input Type=\"text\" name=\"showvalue\" value=\"".$rc->roman1."\" disabled width=\"12\" maxlength=\"12\">\n";
						}
						else
						{
							echo "<input Type=\"text\" name=\"showvalue\" value=\"\" disabled width=\"12\" maxlength=\"12\">\n";
						}
						echo "<input Type=\"hidden\" name=\"decimalcalcvalue\" value=\"".$rc->rollingvalue."\" >\n";
						echo "<input Type=\"hidden\" name=\"calcvalue\" value=\"".$rc->roman1."\" >\n";
						// echo "<input type=\"hidden\" value=\"".$rc."\" name=\"rc\">\n";
					?>
					<input type="hidden" value="1" name="started">
				</td>
				<td>
					<?
						echo "<input Type=\"text\" name=\"showvalue2\" value=\"".$rc->ToRoman($rc->rollingvalue)."\" disabled width=\"12\" maxlength=\"12\">\n";
					?>
				</td>
			</tr>
		</table>

		<table width="230">
			<tr>
				<td>
					<!-- The Number Keys -->
					<table border=1>
						<tr>
							<td>
								 
							</td>
							<td align="center">
								<input type="submit" value="   I   " name="I">
								<? // 1 ?>
							</td>
							<td>
								 
							</td>
						</tr>
						<tr>
							<td>
								<input type="submit" value="   V   " name="V">
								<? // 5 ?>
							</td>
							<td>
								<input type="submit" value="   X    " name="X">
								<? // 10 ?>
							</td>
							<td>
								<input type="submit" value="   L    " name="L">
								<? // 50 ?>
							</td>
						</tr>
						<tr>
							<td>
								<input type="submit" value="   C   " name="C">
								<? // 100 ?> 
							</td>
							<td>
								<input type="submit" value="   D   " name="D">
								<? // 500 ?>
							</td>
							<td>
								<input type="submit" value="   M   " name="M">
								<? // 1000 ?>
							</td>
						</tr>
					</table>
				</td>
				<!-- end of the number keys -->

				<!-- The operations -->
				<td>
					<table>
						<tr>
							<td>
								<input type="submit" value="   +   " name="plus">
								<? // + ?>
							</td>
						</tr>
						<tr>
							<td>
								<input type="submit" value="   -    " name="minus">
								<? // - ?>
							</td>
						</tr>
						<tr>
							<td>
								<input type="submit" value="   x   " name="multiply">
								<? // x ?>
							</td>
						</tr>
						<tr>
							<td>
								<input type="submit" value="   /    " name="divide">
								<? // / ?>
							</td>
						</tr>
					</table>
				</td>
				<!-- End of the operations -->
			</tr>
			<tr>
				<td align="center">
					<!-- Equals, or Calc -->
					<table align="center">
						<tr align="center">					
							<td align="center">
								<input type="submit" value="    =    " name="equals">
								<? // = ?>
							</td>
						</tr>
					</table>
				</td>
				<td>
					<input type="submit" value=" Clear " name="clear"><br>
					<input type="submit" value="Reset " name="reset">
				</td>
			</tr>
		</table>
	</form>
	<p style="color=white">This is a link to a <a href="romancode.htm">code listing</a></p>

</body>
</html>


  A page index