haiku/src/libs/mapm/mapm_gcd.c
Ingo Weinhold 59d799dabc * Moved the mapm library from src/apps/deskcalc to src/libs and headers/libs.
* Moved the ExpressionParser class to shared. It's now built into its own
  static library.
* Added hexadecimal number support to the expression parser as well as
  Evaluation*() methods to get a number instead of a string.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31298 a95241bf-73f2-0310-859d-f6bbb57e9c96
2009-06-28 17:10:40 +00:00

285 lines
5.4 KiB
C

/*
* M_APM - mapm_gcd.c
*
* Copyright (C) 2001 - 2007 Michael C. Ring
*
* Permission to use, copy, and distribute this software and its
* documentation for any purpose with or without fee is hereby granted,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation.
*
* Permission to modify the software is granted. Permission to distribute
* the modified code is granted. Modifications are to be distributed by
* using the file 'license.txt' as a template to modify the file header.
* 'license.txt' is available in the official MAPM distribution.
*
* This software is provided "as is" without express or implied warranty.
*/
/*
* $Id: mapm_gcd.c,v 1.8 2007/12/03 01:41:05 mike Exp $
*
* This file contains the GCD and LCM functions
*
* $Log: mapm_gcd.c,v $
* Revision 1.8 2007/12/03 01:41:05 mike
* Update license
*
* Revision 1.7 2003/07/21 20:16:43 mike
* Modify error messages to be in a consistent format.
*
* Revision 1.6 2003/03/31 22:12:33 mike
* call generic error handling function
*
* Revision 1.5 2002/11/03 22:44:21 mike
* Updated function parameters to use the modern style
*
* Revision 1.4 2002/05/17 22:17:47 mike
* fix comment
*
* Revision 1.3 2002/05/17 22:16:36 mike
* move even/odd util functions to mapmutl2
*
* Revision 1.2 2001/07/15 20:55:20 mike
* add comments
*
* Revision 1.1 2001/07/15 20:48:27 mike
* Initial revision
*/
#include "m_apm_lc.h"
/****************************************************************************/
/*
* From Knuth, The Art of Computer Programming:
*
* This is the binary GCD algorithm as described
* in the book (Algorithm B)
*/
void m_apm_gcd(M_APM r, M_APM u, M_APM v)
{
M_APM tmpM, tmpN, tmpT, tmpU, tmpV;
int kk, kr, mm;
long pow_2;
/* 'is_integer' will return 0 || 1 */
if ((m_apm_is_integer(u) + m_apm_is_integer(v)) != 2)
{
M_apm_log_error_msg(M_APM_RETURN, "\'m_apm_gcd\', Non-integer input");
M_set_to_zero(r);
return;
}
if (u->m_apm_sign == 0)
{
m_apm_absolute_value(r, v);
return;
}
if (v->m_apm_sign == 0)
{
m_apm_absolute_value(r, u);
return;
}
tmpM = M_get_stack_var();
tmpN = M_get_stack_var();
tmpT = M_get_stack_var();
tmpU = M_get_stack_var();
tmpV = M_get_stack_var();
m_apm_absolute_value(tmpU, u);
m_apm_absolute_value(tmpV, v);
/* Step B1 */
kk = 0;
while (TRUE)
{
mm = 1;
if (m_apm_is_odd(tmpU))
break;
mm = 0;
if (m_apm_is_odd(tmpV))
break;
m_apm_multiply(tmpN, MM_0_5, tmpU);
m_apm_copy(tmpU, tmpN);
m_apm_multiply(tmpN, MM_0_5, tmpV);
m_apm_copy(tmpV, tmpN);
kk++;
}
/* Step B2 */
if (mm)
{
m_apm_negate(tmpT, tmpV);
goto B4;
}
m_apm_copy(tmpT, tmpU);
/* Step: */
B3:
m_apm_multiply(tmpN, MM_0_5, tmpT);
m_apm_copy(tmpT, tmpN);
/* Step: */
B4:
if (m_apm_is_even(tmpT))
goto B3;
/* Step B5 */
if (tmpT->m_apm_sign == 1)
m_apm_copy(tmpU, tmpT);
else
m_apm_negate(tmpV, tmpT);
/* Step B6 */
m_apm_subtract(tmpT, tmpU, tmpV);
if (tmpT->m_apm_sign != 0)
goto B3;
/*
* result = U * 2 ^ kk
*/
if (kk == 0)
m_apm_copy(r, tmpU);
else
{
if (kk == 1)
m_apm_multiply(r, tmpU, MM_Two);
if (kk == 2)
m_apm_multiply(r, tmpU, MM_Four);
if (kk >= 3)
{
mm = kk / 28;
kr = kk % 28;
pow_2 = 1L << kr;
if (mm == 0)
{
m_apm_set_long(tmpN, pow_2);
m_apm_multiply(r, tmpU, tmpN);
}
else
{
m_apm_copy(tmpN, MM_One);
m_apm_set_long(tmpM, 0x10000000L); /* 2 ^ 28 */
while (TRUE)
{
m_apm_multiply(tmpT, tmpN, tmpM);
m_apm_copy(tmpN, tmpT);
if (--mm == 0)
break;
}
if (kr == 0)
{
m_apm_multiply(r, tmpU, tmpN);
}
else
{
m_apm_set_long(tmpM, pow_2);
m_apm_multiply(tmpT, tmpN, tmpM);
m_apm_multiply(r, tmpU, tmpT);
}
}
}
}
M_restore_stack(5);
}
/****************************************************************************/
/*
* u * v
* LCM(u,v) = ------------
* GCD(u,v)
*/
void m_apm_lcm(M_APM r, M_APM u, M_APM v)
{
M_APM tmpN, tmpG;
tmpN = M_get_stack_var();
tmpG = M_get_stack_var();
m_apm_multiply(tmpN, u, v);
m_apm_gcd(tmpG, u, v);
m_apm_integer_divide(r, tmpN, tmpG);
M_restore_stack(2);
}
/****************************************************************************/
#ifdef BIG_COMMENT_BLOCK
/*
* traditional GCD included for reference
* (also useful for testing ...)
*/
/*
* From Knuth, The Art of Computer Programming:
*
* To compute GCD(u,v)
*
* A1:
* if (v == 0) return (u)
* A2:
* t = u mod v
* u = v
* v = t
* goto A1
*/
void m_apm_gcd_traditional(M_APM r, M_APM u, M_APM v)
{
M_APM tmpD, tmpN, tmpU, tmpV;
tmpD = M_get_stack_var();
tmpN = M_get_stack_var();
tmpU = M_get_stack_var();
tmpV = M_get_stack_var();
m_apm_absolute_value(tmpU, u);
m_apm_absolute_value(tmpV, v);
while (TRUE)
{
if (tmpV->m_apm_sign == 0)
break;
m_apm_integer_div_rem(tmpD, tmpN, tmpU, tmpV);
m_apm_copy(tmpU, tmpV);
m_apm_copy(tmpV, tmpN);
}
m_apm_copy(r, tmpU);
M_restore_stack(4);
}
/****************************************************************************/
#endif