amath  1.8.5
Simple command line calculator
PositionalNumeralSystem Class Reference

Base class for all numeral systems with a positional notation. More...

#include <ntextp.h>

Inheritance diagram for PositionalNumeralSystem:
Collaboration diagram for PositionalNumeralSystem:

Public Member Functions

 PositionalNumeralSystem (unsigned int base, unsigned int digits, const char fractionPoint)
 
 ~PositionalNumeralSystem ()
 
virtual const char * GetName ()
 
virtual const char * GetPrefix ()
 
virtual unsigned int GetDigits ()
 
virtual void SetDigits (unsigned int digits)
 
virtual const char GetFractionPoint ()
 
virtual void SetFractionPoint (const char fractionPoint)
 
virtual const char * GetText (Number *number)
 
virtual NumberParse (const char *text, unsigned int *length, char **end)
 
- Public Member Functions inherited from NumeralSystem
 NumeralSystem ()
 
virtual ~NumeralSystem ()
 
virtual NumberParse (const char *text)
 

Protected Member Functions

const char * GetSpecialCase (Number *number)
 
void IntegerToBuffer (double value, unsigned int digits, int *outdigits) const
 

Protected Attributes

double baseDouble
 
unsigned int digits
 
char fractionPoint
 
- Protected Attributes inherited from NumeralSystem
CharBufferbuf
 

Private Member Functions

const char * GetText (double number) const
 
bool IsDigit (char *digit)
 

Private Attributes

unsigned int baseInteger
 
char maxNumeric
 
char maxAlphaLower
 
char maxAlphaUpper
 

Detailed Description

Base class for all numeral systems with a positional notation.

More info on positional notation is available at Wikipedia: https://wikipedia.org/wiki/Positional_notation

Definition at line 41 of file ntextp.h.

Constructor & Destructor Documentation

◆ PositionalNumeralSystem()

PositionalNumeralSystem::PositionalNumeralSystem ( unsigned int  base,
unsigned int  digits,
const char  fractionPoint 
)

Definition at line 40 of file ntextp.cpp.

References baseDouble, baseInteger, digits, fractionPoint, maxAlphaLower, maxAlphaUpper, and maxNumeric.

Referenced by DecimalSystem::DecimalSystem(), Program::NewPositionalInput(), and Program::NewPositionalOutput().

43  : digits(digits)
44 {
46  this->baseInteger = base;
47  this->baseDouble = base * 1.0;
48  this->maxNumeric = (base > 10 ? 10 : base) + '0' - 1;
49  this->maxAlphaLower = base > 10 ? base + 'a' - 11 : 0;
50  this->maxAlphaUpper = base > 10 ? base + 'A' - 11 : 0;
51 }
unsigned int digits
Definition: ntextp.h:61
unsigned int baseInteger
Definition: ntextp.h:68
Here is the caller graph for this function:

◆ ~PositionalNumeralSystem()

PositionalNumeralSystem::~PositionalNumeralSystem ( )

Definition at line 53 of file ntextp.cpp.

54 {
55 }

Member Function Documentation

◆ GetDigits()

unsigned int PositionalNumeralSystem::GetDigits ( )
virtual

Implements NumeralSystem.

Definition at line 97 of file ntextp.cpp.

References digits.

98 {
99  return digits;
100 }
unsigned int digits
Definition: ntextp.h:61

◆ GetFractionPoint()

const char PositionalNumeralSystem::GetFractionPoint ( )
virtual

Implements NumeralSystem.

Definition at line 107 of file ntextp.cpp.

References fractionPoint.

108 {
109  return static_cast<const char>(this->fractionPoint);
110 }

◆ GetName()

const char * PositionalNumeralSystem::GetName ( )
virtual

Implements NumeralSystem.

Definition at line 62 of file ntextp.cpp.

References CharBuffer::Append(), baseInteger, NumeralSystem::buf, DecimalSystem::DecimalSystem(), CharBuffer::Empty(), CharBuffer::EnsureSize(), CharBuffer::GetString(), NumeralSystem::GetText(), RealNumber::RealNumber(), and StrLen().

63 {
64  switch (baseInteger)
65  {
66  case 2:
67  return "binary";
68  case 8:
69  return "octal";
70  case 10:
71  return "decimal";
72  case 16:
73  return "hexadecimal";
74  }
75 
76  const char *text = "base ";
77  Number *n = new RealNumber(baseInteger);
78  NumeralSystem *ns = new DecimalSystem(2);
79  const char *numtext = ns->GetText(n);
80 
81  buf->EnsureSize(StrLen(text) + StrLen(numtext) + 1);
82  buf->Empty();
83  buf->Append(text);
84  buf->Append(numtext);
85 
86  delete ns;
87  delete n;
88  return buf->GetString();
89 }
CharBuffer * buf
Definition: ntext.h:65
void Empty()
Definition: charbuf.cpp:218
char * GetString() const
Definition: charbuf.cpp:306
void Append(const char *source)
Definition: charbuf.cpp:262
Definition: numb.h:66
virtual const char * GetText(Number *number)=0
unsigned int baseInteger
Definition: ntextp.h:68
Represent a real number with 15 significant digits.
Definition: real.h:45
int StrLen(const char *string)
Get the length of a null terminated string.
Definition: strlen.c:34
Base class for all numeral systems.
Definition: ntext.h:49
void EnsureSize(unsigned int size)
Ensure a memory block of specified size is allocated.
Definition: charbuf.cpp:114
Here is the call graph for this function:

◆ GetPrefix()

const char * PositionalNumeralSystem::GetPrefix ( )
virtual

Implements NumeralSystem.

Definition at line 91 of file ntextp.cpp.

92 {
93  // TODO: Consider using prefix with numral systems != base 10
94  return EMPTYSTRING;
95 }
#define EMPTYSTRING
Definition: amath.h:213

◆ GetSpecialCase()

const char * PositionalNumeralSystem::GetSpecialCase ( Number number)
protected

Definition at line 117 of file ntextp.cpp.

References CharBuffer::Append(), NumeralSystem::buf, CharBuffer::Empty(), CharBuffer::GetString(), Number::IsInfinite(), Number::IsNaN(), Number::IsNegative(), Number::IsNotImplemented(), and Number::IsZero().

Referenced by DecimalSystem::GetText(), and GetText().

118 {
119  if (number->IsNaN())
120  {
121  buf->Empty();
122  buf->Append("NaN");
123  return buf->GetString();
124  }
125 
126  if (number->IsNotImplemented())
127  {
128  buf->Empty();
129  buf->Append("NotImplemented");
130  return buf->GetString();
131  }
132 
133  if (number->IsInfinite() && number->IsNegative())
134  {
135  buf->Empty();
136  buf->Append("-Inf");
137  return buf->GetString();
138  }
139 
140  if (number->IsInfinite() && !number->IsNegative())
141  {
142  buf->Empty();
143  buf->Append("Inf");
144  return buf->GetString();
145  }
146 
147  if (number->IsZero())
148  {
149  buf->Empty();
150  buf->Append("0");
151  return buf->GetString();
152  }
153 
154  return nullptr;
155 }
virtual bool IsNegative()=0
CharBuffer * buf
Definition: ntext.h:65
void Empty()
Definition: charbuf.cpp:218
char * GetString() const
Definition: charbuf.cpp:306
virtual bool IsInfinite()=0
virtual bool IsZero()=0
void Append(const char *source)
Definition: charbuf.cpp:262
virtual bool IsNotImplemented()=0
virtual bool IsNaN()=0
Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetText() [1/2]

const char * PositionalNumeralSystem::GetText ( Number number)
virtual

Implements NumeralSystem.

Reimplemented in DecimalSystem.

Definition at line 157 of file ntextp.cpp.

References CharBuffer::Append(), NumeralSystem::buf, CharBuffer::CharBuffer(), cimag(), CharBuffer::Copy(), creal(), CharBuffer::Empty(), ComplexNumber::GetComplexValue(), Number::GetRealValue(), GetSpecialCase(), CharBuffer::GetString(), GetText(), nsysreal, and Number::system.

158 {
159  const char *sc = GetSpecialCase(number);
160  if (sc != nullptr)
161  {
162  return sc;
163  }
164 
165  if (number->system == nsysreal)
166  {
167  return GetText(number->GetRealValue());
168  }
169 
170  complex w = static_cast<ComplexNumber *>(number)->GetComplexValue();
171  double a = creal(w);
172  double b = cimag(w);
173 
174  if (a == 0.0 && b == 0.0)
175  {
176  buf->Empty();
177  buf->Append('0');
178  return buf->GetString();
179  }
180 
181  CharBuffer *val = new CharBuffer(512);
182  val->Empty();
183 
184  if (a != 0.0)
185  {
186  const char *real = GetText(a);
187  val->Append(real);
188  }
189 
190  const char *imag = GetText(b);
191  if (a != 0.0 && b > 0.0)
192  {
193  val->Append('+');
194  }
195 
196  if (b != 0.0)
197  {
198  val->Append(imag);
199  val->Append('i');
200  }
201 
202  buf->Copy(val);
203  delete val;
204 
205  return buf->GetString();
206 }
CharBuffer * buf
Definition: ntext.h:65
Definition: mathi.h:48
void Empty()
Definition: charbuf.cpp:218
double cimag(complex z)
Imaginary part of complex number.
Definition: prim.c:46
char * GetString() const
Definition: charbuf.cpp:306
NumberSystem system
Definition: numb.h:171
void Append(const char *source)
Definition: charbuf.cpp:262
const char * GetSpecialCase(Number *number)
Definition: ntextp.cpp:117
double creal(complex z)
Real part of complex number.
Definition: prim.c:38
virtual const char * GetText(Number *number)
Definition: ntextp.cpp:157
virtual double GetRealValue()=0
Represent a complex number with 2 components of 15 significant digits.
Definition: cplex.h:46
void Copy(CharBuffer *buf)
Definition: charbuf.cpp:233
Encapsulate an character array which can be used as a string.
Definition: charbuf.h:44
Definition: numb.h:61
Here is the call graph for this function:

◆ GetText() [2/2]

const char * PositionalNumeralSystem::GetText ( double  number) const
private

Definition at line 208 of file ntextp.cpp.

References CharBuffer::Append(), baseDouble, NumeralSystem::buf, digits, CharBuffer::Empty(), fabs(), FloatUnion64::floatingPoint, fractionPoint, CharBuffer::GetString(), IntegerToBuffer(), CharBuffer::Is(), FloatUnion64::IsInf(), log2p(), pow(), CharBuffer::RemoveTrailing(), round(), and trunc().

Referenced by GetText().

209 {
210  if (number == 0.0)
211  {
212  return "0";
213  }
214 
215  buf->Empty();
216 
217  double dnumber = number;
218  if (dnumber < 0.0)
219  {
220  buf->Append('-');
221  dnumber = -dnumber;
222  }
223 
224  double expbor = log2p(baseDouble, dnumber);
225  double expacc = expbor > 0.0 ? 4e-14 : -1e-15;
226  double expborder = trunc(expbor + expacc);
227 
228  int exponent = 0;
229  double rounding;
230 
231  double bordermax = trunc(9.0 * 10 / baseDouble);
232  double bordermin = trunc(-8.0 * 10 / baseDouble);
233 
234  // Find exponent
235  if (expborder >= bordermax || expborder <= bordermin)
236  {
237  double dexp = trunc(log2p(baseDouble, dnumber) + expacc);
238  dnumber = dnumber * pow(baseDouble, -dexp);
239 
240  // pow is inaccurate on small and large numbers
241  if (dexp > 15 || dexp < -15)
242  {
243  dnumber += 2e-15;
244  }
245 
246  // Adjust if below zero
247  if (dnumber < 1.0)
248  {
249  dexp--;
250  dnumber *= baseDouble;
251  }
252 
253  exponent = static_cast<int>(dexp);
254  rounding = 0;
255  }
256  else
257  {
258  double acc = exponent > 0 ? 15 : -15;
259  rounding = pow(baseDouble, exponent + acc);
260  }
261 
262  int digitout;
263  int intdigits;
264 
265  double intvalue = trunc(dnumber + rounding);
266  IntegerToBuffer(intvalue, digits, &intdigits);
267 
268  int fragdigits = digits - intdigits + (intvalue < 1.0 ? 1 : 0);
269  if (fragdigits > 0)
270  {
272 
273  double fraction = fabs(round((dnumber - intvalue) * pow(baseDouble, fragdigits)));
274  double temp1 = log2p(baseDouble, fraction);
275  FloatUnion64 temp2;
276  temp2.floatingPoint = temp1;
277  bool fin = !temp2.IsInf();
278  int actualdigits = static_cast<int>(trunc(temp1 + 3e-15));
279  int padding = fragdigits - (fin == 1 ? actualdigits : 0) - 1;
280 
281  // Pad zeros if needed
282  while (padding-- > 0)
283  {
284  buf->Append('0');
285  }
286 
287  intvalue = static_cast<int64_t>(trunc(fraction * baseDouble) / baseDouble);
288  IntegerToBuffer(intvalue, fragdigits, &digitout);
289 
290  // Remove trailing zeros
291  // ReSharper disable once CppPossiblyErroneousEmptyStatements
292  while (buf->RemoveTrailing('0'))
293  ;
294 
296  }
297 
298  // Add exponent
299  if (exponent != 0)
300  {
301  buf->Append('e');
302  buf->Append(exponent > 0 ? '+' : '-');
303  IntegerToBuffer(abs(exponent), 3, &digitout);
304  }
305 
306  // Make sure no rounding error is returned
307  if (buf->Is("-0"))
308  {
309  buf->Empty();
310  buf->Append('0');
311  }
312 
313  return buf->GetString();
314 }
#define abs(x)
Definition: mathr.h:55
CharBuffer * buf
Definition: ntext.h:65
double log2p(double x, double y)
Definition: log2p.c:32
unsigned int digits
Definition: ntextp.h:61
void Empty()
Definition: charbuf.cpp:218
char * GetString() const
Definition: charbuf.cpp:306
void IntegerToBuffer(double value, unsigned int digits, int *outdigits) const
Definition: ntextp.cpp:316
bool RemoveTrailing(const char c)
Definition: charbuf.cpp:270
bool Is(const char *string) const
Compare content of CharBuffer with string)
Definition: charbuf.cpp:194
void Append(const char *source)
Definition: charbuf.cpp:262
bool IsInf() const
Definition: numb.h:47
double pow(double x, double y)
Expontation function.
Definition: pow.c:138
double floatingPoint
Definition: numb.h:53
double fabs(double x)
Returns the absolute value of x.
Definition: fabs.c:51
double trunc(double x)
Truncate function.
Definition: trunc.c:52
double round(double x)
Round function.
Definition: round.c:40
Here is the call graph for this function:
Here is the caller graph for this function:

◆ IntegerToBuffer()

void PositionalNumeralSystem::IntegerToBuffer ( double  value,
unsigned int  digits,
int *  outdigits 
) const
protected

Definition at line 316 of file ntextp.cpp.

References CharBuffer::Append(), baseDouble, NumeralSystem::buf, fmod(), and trunc().

Referenced by DecimalSystem::GetText(), and GetText().

317 {
318  static const char *alphaNumerics = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
319  unsigned int count = 0;
320  char *chars = new char[128];
321  char *start = chars;
322 
323  do
324  {
325  count++;
326  unsigned int intremainder = static_cast<unsigned int>(trunc(fmod(value, baseDouble)));
327  *chars++ = alphaNumerics[intremainder];
328  value /= baseDouble;
329  } while (value >= 1.0);
330 
331  unsigned int n = count;
332  unsigned int q = digits;
333  chars--;
334 
335  while (n-- != 0 && q-- != 0)
336  {
337  buf->Append(*chars--);
338  }
339 
340  n++;
341  while (n-- != 0)
342  {
343  buf->Append('0');
344  }
345 
346  *outdigits = count;
347  delete[] start;
348 }
CharBuffer * buf
Definition: ntext.h:65
unsigned int digits
Definition: ntextp.h:61
void Append(const char *source)
Definition: charbuf.cpp:262
double fmod(double x, double y)
Return x mod y in exact arithmetic.
Definition: fmod.c:58
double trunc(double x)
Truncate function.
Definition: trunc.c:52
Here is the call graph for this function:
Here is the caller graph for this function:

◆ IsDigit()

bool PositionalNumeralSystem::IsDigit ( char *  digit)
private

Definition at line 57 of file ntextp.cpp.

58 {
59  return true;
60 }

◆ Parse()

Number * PositionalNumeralSystem::Parse ( const char *  text,
unsigned int *  length,
char **  end 
)
virtual

Implements NumeralSystem.

Definition at line 350 of file ntextp.cpp.

References baseDouble, fractionPoint, maxAlphaLower, maxAlphaUpper, maxNumeric, pow(), and RealNumber::RealNumber().

351 {
352  unsigned int pos = 0;
353  double integer = 0;
354  bool done = false;
355 
356  // Parse integer part of number
357  do
358  {
359  double addition;
360  if (*text == '\0')
361  {
362  done = true;
363  continue;
364  }
365 
366  if (*text >= '0' && *text <= maxNumeric)
367  {
368  addition = (*text - '0') * 1.0;
369  }
370  else if (maxAlphaUpper != 0 && *text >= 'A' && *text <= maxAlphaUpper)
371  {
372  addition = (*text - 'A' + 10) * 1.0;
373  }
374  else if (maxAlphaLower != 0 && *text >= 'a' && *text <= maxAlphaLower)
375  {
376  addition = (*text - 'a' + 10) * 1.0;
377  }
378  else
379  {
380  done = true;
381  continue;
382  }
383 
384  integer = integer * baseDouble + addition;
385  text++;
386  pos++;
387  } while (!done);
388 
389  // Digits not found
390  if (pos == 0)
391  {
392  *length = 0;
393  *end = const_cast<char *>(text);
394  return new RealNumber();
395  }
396 
397  // Parse fraction part of number
398  double fraction = 0.0;
399  double divisor = 1.0;
400  if (*text == fractionPoint && fractionPoint != '\0')
401  {
402  done = false;
403  double addition;
404  text++;
405  pos++;
406 
407  do
408  {
409  if (*text == '\0')
410  {
411  done = true;
412  continue;
413  }
414 
415  if (*text >= '0' && *text <= maxNumeric)
416  {
417  addition = (*text - '0') * 1.0;
418  }
419  else if (maxAlphaUpper != 0 && *text >= 'A' && *text <= maxAlphaUpper)
420  {
421  addition = (*text - 'A' + 10) * 1.0;
422  }
423  else if (maxAlphaLower != 0 && *text >= 'a' && *text <= maxAlphaLower)
424  {
425  addition = (*text - 'a' + 10) * 1.0;
426  }
427  else
428  {
429  done = true;
430  continue;
431  }
432 
433  fraction = fraction * baseDouble + addition;
434  divisor *= baseDouble;
435  text++;
436  pos++;
437  } while (!done);
438  }
439 
440  // Parse exponent part of number
441  double exp = 0.0;
442  if (*text == 'e' || *text == 'E')
443  {
444  double addition;
445  text++;
446  pos++;
447 
448  double sign = *text == '+' ? 1.0 : *text == '-' ? -1.0 : 0.0;
449 
450  if (sign != 0.0)
451  {
452  done = false;
453  text++;
454  pos++;
455 
456  do
457  {
458  if (*text == '\0')
459  {
460  done = true;
461  continue;
462  }
463 
464  if (*text >= '0' && *text <= maxNumeric)
465  {
466  addition = (*text - '0') * 1.0;
467  }
468  else if (maxAlphaUpper != 0 && *text >= 'A' && *text <= maxAlphaUpper)
469  {
470  addition = (*text - 'A' + 10) * 1.0;
471  }
472  else if (maxAlphaLower != 0 && *text >= 'a' && *text <= maxAlphaLower)
473  {
474  addition = (*text - 'a' + 10) * 1.0;
475  }
476  else
477  {
478  done = true;
479  continue;
480  }
481 
482  exp = exp * baseDouble + addition;
483  text++;
484  pos++;
485  } while (!done);
486  exp *= sign;
487  }
488  else
489  {
490  text--;
491  pos--;
492  }
493  }
494 
495  *length = pos;
496  *end = const_cast<char *>(text);
497 
498  double dnumber = (integer + (fraction / divisor));
499 
500  if (exp != 0.0)
501  {
502  // pow seems a bit off
503  dnumber *= pow(baseDouble, exp + 4e-15);
504  }
505 
506  return new RealNumber(dnumber);
507 }
double pow(double x, double y)
Expontation function.
Definition: pow.c:138
Represent a real number with 15 significant digits.
Definition: real.h:45
double exp(double x)
Returns the exponential of x.
Definition: exp.c:138
Here is the call graph for this function:

◆ SetDigits()

void PositionalNumeralSystem::SetDigits ( unsigned int  digits)
virtual

Implements NumeralSystem.

Definition at line 102 of file ntextp.cpp.

References digits.

103 {
104  this->digits = digits;
105 }
unsigned int digits
Definition: ntextp.h:61

◆ SetFractionPoint()

void PositionalNumeralSystem::SetFractionPoint ( const char  fractionPoint)
virtual

Implements NumeralSystem.

Definition at line 112 of file ntextp.cpp.

References fractionPoint.

113 {
115 }

Member Data Documentation

◆ baseDouble

double PositionalNumeralSystem::baseDouble
protected

Definition at line 60 of file ntextp.h.

Referenced by GetText(), IntegerToBuffer(), Parse(), and PositionalNumeralSystem().

◆ baseInteger

unsigned int PositionalNumeralSystem::baseInteger
private

Definition at line 68 of file ntextp.h.

Referenced by GetName(), and PositionalNumeralSystem().

◆ digits

unsigned int PositionalNumeralSystem::digits
protected

◆ fractionPoint

char PositionalNumeralSystem::fractionPoint
protected

◆ maxAlphaLower

char PositionalNumeralSystem::maxAlphaLower
private

Definition at line 70 of file ntextp.h.

Referenced by Parse(), and PositionalNumeralSystem().

◆ maxAlphaUpper

char PositionalNumeralSystem::maxAlphaUpper
private

Definition at line 71 of file ntextp.h.

Referenced by Parse(), and PositionalNumeralSystem().

◆ maxNumeric

char PositionalNumeralSystem::maxNumeric
private

Definition at line 69 of file ntextp.h.

Referenced by Parse(), and PositionalNumeralSystem().


The documentation for this class was generated from the following files: