libMVRgdtf 40bc00a
A library for GDTF and MVR
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
MCFloat.h
Go to the documentation of this file.
1//
2// Copyright Nemetschek Vectorworks, Inc.
3// Use of this file is governed by the Nemetschek Vectorworks SDK License Agreement
4// http://developer.vectorworks.net/index.php?title=Vectorworks_SDK_License
5//
6// Declares most of the standard floating point data types used
7// in MiniCad & external code.
8//
9
10
11#ifndef _MCFLOAT_
12#define _MCFLOAT_
13
14#pragma once
15
16#include <cfloat>
17
18// XXX_JDW_ALTURA CLEANUP [2003-05-15]
19#if GS_WIN
20#include <math.h> // Want non-std defs of fabs, etc. for consistency with Windows,
21#else
22#include <cmath>
23#endif
24 // so use this instead of <math.h> or <cmath>. Also provides
25 // 80-bit floating-point functions. MFH 03/01
26// TODO before included <fp.h> for the Mac. Non-existant now in GCC.
27#include "GSUtil.h"
28
29// short double 64 bits
30// double 64 bits
31// long double 64 bits
32
33namespace VectorworksMVR
34{
37
38#define double80(x) Real64 x; short x##_pad
39
40 typedef const float_gs float_param;
41 typedef const double_gs double_param;
42
43
44 /* The following functions and classes convert the ten bytes pointed to between an 80-bit number and
45 a 64-bit number with 16 bits of padding on the end. USE WITH EXTREME CAUTION!
46 */
47
49 // extended80_gs
51 //
52 // extended80_gs is Diehl Graphsoft's standard 80-bit floating point raw data storage type.
53 //
54 // On 68k platforms, it is a natively-supported extended.
55 //
56 // On all other platforms it is a structure containing 10 bytes which must be specifically
57 // converted to a floating point value before use. The Extended80 class is intended to
58 // do this transparently in most instances.
59 //
60 // In some isolated cases, extended80_gs can be used directly, but great care must be used
61 // to access it correctly or you will get incorrect results.
62 //
63 // extended80_gs can be freely cast to and from the Macintosh extended80 type, but we no longer
64 // use that type directly in order to achieve greater platform independence.
65 //
66
67 struct extended80_gs { short w[5]; };
69
70
71
72#if GS_LITTLE_ENDIAN
73#if GS_MAC
74 double GS_API x80todNNA(const extended80 *x80);
75 void GS_API dtox80NNA(const double *x, extended80 *x80);
76#else
77 /* These functions are defined in the 2.0 version of fp.x, but the Windows folk
78 are still using 1.0, so they're defined here. This bit should be removed
79 when everyone is using Universal Headers 2.0.
80 */
81 double GS_API x80tod(const extended80_gs *x80);
82 void GS_API dtox80(const double *x, extended80_gs *x80);
83#endif
84#else
85 // PowerMac versions of these are provided by the system and take a true extended80
86#endif
87
88#if BUG
89
90 inline void ASSERT4BYTEALIGNMENT(const void *p, const char *name)
91 {
92 if (((size_t)p % 4) != 0)
93 DSTOP((kBruce, "Misaligned floating point access to %s - SERIOUS PERFORMANCE PENALTY!", name));
94 }
95#define ASSERT4BYTEALIGNMENT(p, s) ASSERT4BYTEALIGNMENT(p, s)
96
97#else
98
99#define ASSERT4BYTEALIGNMENT(p, s) DEBUG_DO_NOTHING
100
101#endif
102
103
104//----------------------------------------------------------------------------------------
105
106// I've decided to add a fudge factor below because WorldToViewCoordX, for example,
107// would wind up with a value of 52.49999999999994 when using the speed factors
108// WorldToViewXOffset and WorldToViewFactor, but would come up with the value of
109// exactly 52.5 when calculated using the more drawn out (but mathematically identical)
110// method. This was causing some unsightly one pixel off drawing behaviors.
111//
112// I put the additive factor at the 10th digit because doubles have 15 digits of precision
113// and a short can have 5 digits to the left of the decimal point, so this should fix
114// one off problems even for even very large short values. I can't believe a number like
115// 52.49999999999994 comes through here very often that actually needs to be rounded
116// down to 52. It's much more likely that it "means to be" 52.5.
117//
118// I'm not as comfortable doing this for DoubleToLong, so I'm not going to unless the need
119// presents itself. [MAF 8/18/00]
120
121
122 BUG_ONLY(void AssertNum2Short(double x));
123
124 force_inline short Num2Short(double x)
125{
126 BUG_ONLY(AssertNum2Short(x));
127
128 return (x > 32767) ? (short) 32767 :
129 (x < -32767) ? (short) -32767 :
130 (x > 0) ? (short) (x + 0.5000000001) :
131 (x < 0) ? (short) (x - 0.5000000001) :
132 (short) 0;
133}
134
135//----------------------------------------------------------------------------------------
136
137 BUG_ONLY(void AssertDoubleToLong(double x));
138
139 inline Sint32 DoubleToLong(double x)
140{
141 BUG_ONLY(AssertDoubleToLong(x));
142
143 return (x > INT32_MAX) ? (Sint32) INT32_MAX :
144 (x < INT32_MIN) ? (Sint32) INT32_MIN:
145 (x > 0) ? (Sint32) (x + 0.5) :
146 (x < 0) ? (Sint32) (x - 0.5) :
147 (Sint32) 0;
148}
149
150//----------------------------------------------------------------------------------------
151
152 // XXX_JDW_ALTURA [2003-05-14] - are we using full precision on windows? maybe our
153 // settings should be adjusted so mac and windows have the same floating point behaviors
154 /*
155 "Floating-point precision of intermediate values is controlled by the _controlfp.
156 By default, _controlfp's precision control is set to 53 bits (_PC_53).
157 Linking with FP10.OBJ changes the default precision control to 64 bits (_PC_64).
158 On the linker command line, FP10.OBJ must appear before LIBC.LIB, LIBCMT.LIB, or MSVCRT.LIB."*/
159
160
162#if _WINDOWS
164
165/*
166C9X FUNCTION MICROSOFTEQUIVALENT
167copysign() _copysign()
168fmax() __max()
169fmin() __min()
170fpclassify() _fpclass()
171hypot() _hypot()
172isfinite() _finite()
173isnan() _isnan()
174logb() _logb()
175nextafter() _nextafter()
176scalb() _scalb
177*/
178
179// from Apple's fp.h
180
181
182// Decimal numbers
183
184#define FLOATDECIMAL ((char)(0))
185#define FIXEDDECIMAL ((char)(1))
186
187// XXX_JDW_ALTURA [2003-05-14] - maybe change this to 36 like Mac version
188#define SIGDIGLEN 20
189
190 struct decimal {
191 char sgn; /* sign 0 for +, 1 for - */
192 char unused;
193 short exp; /* decimal exponent */
194 struct {
195 unsigned char length;
196 unsigned char text[SIGDIGLEN]; /* significant digits */
197 unsigned char unused;
198 } sig;
199 };
200
201 struct decform {
202 char style; /* FLOATDECIMAL or FIXEDDECIMAL */
203 char unused;
204 short digits;
205 };
206
207 void num2dec(const decform *f, double x, decimal *d);
208 double dec2num(const decimal *d);
209
210 // Relational operators
211
212typedef short relop; /* relational operator */
213enum {
214 GREATERTHAN = ( ( relop ) ( 0 ) ),
215 LESSTHAN,
216 EQUALTO,
217 UNORDERED
218 };
219
220
221 // Floating point classification
222
223#define DOUBLE_SIZE 8
224
225enum {
226 FP_SNAN = 3, /* signaling NaN */
227 FP_QNAN = 4, /* quiet NaN */
228};
229
230
231inline bool IsNAN (double v) { return _isnan(v)!=0; }
232inline bool IsFinite (double v) { return _finite(v)!=0; }
233inline bool IsInfinite (double v) { return !_finite(v)==0; }
234 Sint32 FPClassify (double v);
235
237#elif _LINUX
239
240// from Apple's fp.h
241
242
243// Decimal numbers
244
245#define FLOATDECIMAL ((char)(0))
246#define FIXEDDECIMAL ((char)(1))
247
248// XXX_JDW_ALTURA [2003-05-14] - maybe change this to 36 like Mac version
249#define SIGDIGLEN 20
250
251 struct decimal {
252 char sgn; /* sign 0 for +, 1 for - */
253 char unused;
254 short exp; /* decimal exponent */
255 struct {
256 unsigned char length;
257 unsigned char text[SIGDIGLEN]; /* significant digits */
258 unsigned char unused;
259 } sig;
260 };
261
262 struct decform {
263 char style; /* FLOATDECIMAL or FIXEDDECIMAL */
264 char unused;
265 short digits;
266 };
267
268 void num2dec(const decform *f, double x, decimal *d);
269 double dec2num(const decimal *d);
270
271 // Relational operators
272
273typedef short relop; /* relational operator */
274enum {
275GREATERTHAN = ( ( relop ) ( 0 ) ),
276LESSTHAN,
277EQUALTO,
278UNORDERED
279 };
280
281
282 // Floating point classification
283
284#define DOUBLE_SIZE 8
285
286enum {
287 FP_SNAN = 3, /* signaling NaN */
288 FP_QNAN = 4, /* quiet NaN */
289};
290inline bool IsNAN (double v) { return std::isnan(v); }
291inline bool IsFinite (double v) { return std::isfinite(v); }
292inline bool IsInfinite (double v) { return !std::isfinite(v); }
293inline Sint32 FPClassify (double v) { return std::fpclassify(v); }
294
296#else // Mac
298
299inline bool IsNAN (double v) { return std::isnan(v); }
300inline bool IsFinite (double v) { return std::isfinite(v); }
301inline bool IsInfinite (double v) { return !std::isfinite(v); }
302inline Sint32 FPClassify (double v) { return std::fpclassify(v); }
303
305#endif
307
308// note - denormal numbers are numbers that are almost zero; on some platforms calculations on denormal
309// numbers are done in software emulation instead of on the chip, making them much slower.
310
311inline bool IsLegal (double v) { return setmember(FPClassify(v), (Sint32)FP_NORMAL, (Sint32)FP_SUBNORMAL, (Sint32)FP_ZERO); }
312inline bool IsIllegal (double v) { return !setmember(FPClassify(v), (Sint32)FP_NORMAL, (Sint32)FP_SUBNORMAL, (Sint32)FP_ZERO); }
313inline bool IsZeroOrDenormal (double v) { return setmember(FPClassify(v), (Sint32)FP_ZERO, (Sint32)FP_SUBNORMAL); }
314
315
317 // Cross-Platform byte swapping & conversion functions
319
321
322 // Moved to GSUtil.h. [MAF 10/10/02]
323 // void GS_API ByteSwapDouble(Real64 *p);
324
326 //
327 // ByteSwapDOUBLE80 is really the same as ByteSwapEXTENDED80, but it's used
328 // for the types which needed ConvertFP in the past. Since FP types are now
329 // stored as 8 byte doubles on disk now, this simply serves as a reminder
330 // of how the types differ in older versions of the file format.
331 //
333
335
336
338 // FP switch enumerations
340 // The following allow filing code to be written in a much more human-readable form,
341 // which is a bug win since filing is so error prone.
342 //
343
344 // for ConvertFP conversion direction parameter
349
350 // for ConvertFP nativeByteOrder parameter
355
356 // for ByteSwap floating point format parameter
361
362
364 // ByteSwapFP
366 // This is the general floating point ByteSwap routine for swapping either
367 // 64 or 80 bit floating point values. It swaps either 8 or 10 bytes depending
368 // on the fpFormat parameter passed.
369 //
370
371
372 // Duped from GSUtil.h. Where does this go so theat everyone who needs it can get to it?? [MAF 10/10/02]
373inline void ByteSwapDoubleMAF(double *pld)
374{
375 char t;
376 char *pb1 = (char *) pld;
377 char *pb2 = pb1 + sizeof(Real64) - 1;
378 while (pb2 > pb1) {
379 t = *pb1;
380 *pb1 = *pb2;
381 *pb2 = t;
382 ++pb1;
383 --pb2;
384 }
385 }
386
387
388
389
391 {
392 if (archaicDouble)
393 return kArchaicFP; // swap 10 byte doubles
394 else
395 return kModernFP; // swap 8 byte doubles
396 }
397
398 inline void ByteSwapFP(void* fpValue, EByteSwapFPMode fpFormat)
399 {
400 if (fpFormat == kArchaicFP) {
402 }
403 else {
404 ASSERTN(kEveryone, fpFormat == kModernFP);
405 ByteSwapDoubleMAF((Real64 *)fpValue);
406 }
407 }
408
410 // ConvertFP
412 // This is the preferred floating point translation routine for converting between
413 // 64 & 80 bit floating point values. It requires the value to be in an 80 bit field
414 // because it converts in place. It handles data in native and non-native byte order.
415 //
416
417 inline EFPByteOrder ByteOrder(Bool8 needsSwapping)
418 {
419 return needsSwapping ? kNeedsByteSwapping : kNativeByteOrder;
420 }
421
422
423 /*============================================================================*/
424
425#if GS_WIN
426#define Fabs fastFabs
427
428#else // mac
429
430#define Fabs fabs
431#endif
432
433
434 const extern double kNearlyEqualEpsilonForDoubles;
435 const extern double kNearlyEqualEpsilonForNormalizedValues;
436
437
438 //----------------------------------------------------------------------------------------
439 //
440 // Magnitude-based double Comparison Functions.
441 //
442 // All double comparisons should use these functions.
443 //
444 // These double comparison functions are necessary because most floating point numbers
445 // that are not whole numbers cannot be represented exactly (they have floating point
446 // approximations). Double precision floating point numbers (doubles) are accurate to 15
447 // digits, but we'll consider doubles equal if they are the same up to the 13th significant
448 // digit (to allow for drift). Note that these functions must and do take the magnitude of the
449 // values into account. 100,000,000,000,000 must be considered equal to 100,000,000,000,001,
450 // and 1.00000000000000 must be considered equal to 1.00000000000001. [MAF 5/20/02]
451 //
452 // Note this exception: very small numbers that are not relatively close to each other are still
453 // considered equal. This prevents us from doing nanocircuit design, but much of our application
454 // depends on this. For example:
455 //
456 // 1.233 is considered NOT nearly equal to 1.234
457 // 1.233e+15 is considered NOT nearly equal to 1.234e+15
458 // but 1.233e-15 IS considered nearly equal to 1.234e-15,
459 //
460 // because parts of our application need values that are very nearly zero to be considered zero.
461 //
462 //----------------------------------------------------------------------------------------
463 force_inline Boolean DoublesAreNearlyEqual(const double& n1, const double& n2,
464 double epsilon = kNearlyEqualEpsilonForDoubles)
465 {
466 // return (Abs(1 - (n2 / n1)) < epsilon);
467
468 // Factor out the division for speed and div0. Also, always use the
469 // larger value * epsilon so that DoublesAreNearlyEqual(x,y) == DoublesAreNearlyEqual(y,x)
470 // IFed out by JDW 2003-11-20 - fails if you have very different very small numbers (ie 1/parsecs == 1/lightyears in dxf units testing)
471 // IFed back in by JDW 2003-12-23 - fails if you use create rectangle and enter .5 tab .5 tab .5 tab - first no longer displays as fraction
472 double abs_n1 = Fabs(n1);
473 double abs_n2 = Fabs(n2);
474 double abs_n1n2 = Fabs(n1 - n2);
475#if 1
476 if ((abs_n1 <= epsilon) || (abs_n2 <= epsilon)) // if either is very nearly zero, don't take the magnitude into account
477 return (abs_n1n2 <= epsilon);
478 else
479#endif
480 return (abs_n1n2 <= ( abs_n1 > abs_n2 ? abs_n1 : abs_n2 ) * epsilon);
481}
482
484 {
485 return DoublesAreNearlyEqual(n, 0);
486 }
487
488 inline Boolean DoublesAreNotNearlyEqual(double n1, double n2)
489 {
490 return (!DoublesAreNearlyEqual(n1, n2));
491 }
492
493 inline Boolean Double1_GE_Double2(double n1, double n2)
494 {
495 return ((n1 > n2) || DoublesAreNearlyEqual(n1, n2));
496 }
497
498inline Boolean Double1_GT_Double2(double n1, double n2)
499{
500 return ((n1 > n2) && (! DoublesAreNearlyEqual(n1, n2)));
501}
502
503inline Boolean Double1_LE_Double2(double n1, double n2)
504 {
505 return ((n1 < n2) || DoublesAreNearlyEqual(n1, n2));
506 }
507
508inline Boolean Double1_LT_Double2(double n1, double n2)
509{
510 return ((n1 < n2) && (! DoublesAreNearlyEqual(n1, n2)));
511}
512
513//----------------------------------------------------------------------------------------
514
515 inline bool NearlyEqualFixedTolerance(double a, double b, double tolerance)
516// Not using DoublesAreNearlyEqual because I need a fixed tolerance to match
517// what other text tolerance routines are doing - esp in DrawPad - PCP
518{
519 return (fabs(a-b) < tolerance);
520}
521
523 {
525 }
526
527 //----------------------------------------------------------------------------------------
528
529 //----------------------------------------------------------------------------------------
530 //
531 // Magnitude-based double Comparison Functions For Normalized Values.
532 //
533 // All double comparisons for doubles that contain normalized values should use these functions.
534 //
535 // These double comparison functions are necessary because most floating point numbers
536 // that are not whole numbers cannot be represented exactly (they have floating point
537 // approximations). Double precision floating point numbers (doubles) are accurate to 15
538 // digits, but we'll consider normalized value equal if they are the same up to the 6th significant
539 // digit (see kNearlyEqualEpsilonForNormalizedValues in MCFloat.cpp for reasons why). [MAF 5/20/02]
540 //
541 //----------------------------------------------------------------------------------------
542
543
544
545 inline Boolean NormalizedValuesAreNearlyEqual(double n1, double n2)
546 {
547 //ASSERTN(kMark, (IsANormalizedValue(n1) && IsANormalizedValue(n2)));
548
549 // Factor out the division for speed and div0. Also, always use the
550 // larger value * epsilon so that DoublesAreNearlyEqual(x,y) == DoublesAreNearlyEqual(y,x)
551 if ((n1 == 0) || (n2 == 0))
552 return (fastFabs(n1 - n2) <= kNearlyEqualEpsilonForNormalizedValues);
553 else
554 return (fastFabs(n1 - n2) <= ( fastFabs(n1) > fastFabs(n2) ? fastFabs(n1) : fastFabs(n2) ) * kNearlyEqualEpsilonForNormalizedValues);
555}
556
558 {
560 }
561
563 {
565 }
566
567 //----------------------------------------------------------------------------------------
568
569
573 double Modf(const double inNum, double* outIntegralPart,
574 const double inEpsilon = kNearlyEqualEpsilonForDoubles);
575
576
578 force_inline float DoubleToFloat(double dblVal)
579 //
580 // We use this func in case we ever end up needing it to
581 // check for overflow.
583 {
584 double pinnedDouble = PinTo<float>(kEveryone, dblVal);
585 ASSERTN(kEveryone, (pinnedDouble == dblVal));
586
587 return (float) pinnedDouble;
588}
589
590
591 //**************************************************************************
592 //
593 // Data Structures Used By: NNAFrac2X, NNAFix2X, NNAX2Fix, NNAX2Frac, NNAFracMul, &
594 // NNALong2Fix
595 //
596 //**************************************************************************
597
598 //**************************************************************************
599 //
600 // NNAFixed 16-bit signed integer plus 16-bit fraction
601 // to represent fixed-point decimal
602 // numbers in the interval:
603 //
604 // [-32768, 32767 + ((2^16 - 1)/2^16)]
605 //
606 //**************************************************************************
607
610
617
618}
619#endif // _MCFLOAT_
unsigned char Bool8
Definition GSTypes.h:79
int32_t Sint32
Definition GSTypes.h:36
float Real32
Definition GSTypes.h:65
double Real64
Definition GSTypes.h:66
unsigned char Boolean
Definition GSTypes.h:111
#define ASSERT4BYTEALIGNMENT(p, s)
Definition MCFloat.h:99
#define Fabs
Definition MCFloat.h:430
#define DSTOP(params)
Definition StdAfx.h:38
#define ASSERTN(x, y)
Definition StdAfx.h:37
#define GS_API
Definition StdAfx.h:46
#define kEveryone
Definition StdAfx.h:43
Definition CieColor.h:9
Boolean NormalizedValueIsNearlyZero(double n)
Definition MCFloat.h:557
bool IsLegal(double v)
Definition MCFloat.h:311
Sint32 FPClassify(double v)
Definition MCFloat.h:302
BUG_ONLY(void AssertNum2Short(double x))
void GS_API ByteSwapEXTENDED80(extended80_gs *p)
bool NearlyEqualFixedTolerance(double a, double b, double tolerance)
Definition MCFloat.h:515
Boolean IsANormalizedValue(double n)
Definition MCFloat.h:522
double WholeNumberDigitsPow10PinE16(double_param inValue)
bool IsNAN(double v)
Definition MCFloat.h:299
Boolean Double1_LE_Double2(double n1, double n2)
Definition MCFloat.h:503
EFPDirection
Definition MCFloat.h:345
@ kConvert64to80FP
Definition MCFloat.h:346
@ kConvert80to64FP
Definition MCFloat.h:347
Boolean Double1_GT_Double2(double n1, double n2)
Definition MCFloat.h:498
const float_gs float_param
Definition MCFloat.h:40
double Modf(const double inNum, double *outIntegralPart, const double inEpsilon=kNearlyEqualEpsilonForDoubles)
double NNAFix2X(NNAFixed x)
EFPByteOrder ByteOrder(Bool8 needsSwapping)
Definition MCFloat.h:417
NNAFract NNAFracMul(NNAFract x, NNAFract y)
const double_gs double_param
Definition MCFloat.h:41
short WholeNumberDigitsPin16(double_param inValue)
void ByteSwapFP(void *fpValue, EByteSwapFPMode fpFormat)
Definition MCFloat.h:398
force_inline short Num2Short(double x)
Definition MCFloat.h:124
NNAFixed NNAX2Fix(double x)
const double kNearlyEqualEpsilonForDoubles
Definition MCFloat.cpp:14
Boolean NormalizedValueIsNearlyOne(double n)
Definition MCFloat.h:562
double NNAFrac2X(NNAFract x)
Sint32 NNAFixed
Definition MCFloat.h:608
EByteSwapFPMode ByteSwapFPMode(Bool8 archaicDouble)
Definition MCFloat.h:390
Boolean DoubleIsNearlyZero(double n)
Definition MCFloat.h:483
bool IsIllegal(double v)
Definition MCFloat.h:312
bool IsFinite(double v)
Definition MCFloat.h:300
Real32 float_gs
Definition MCFloat.h:36
EByteSwapFPMode
Definition MCFloat.h:357
@ kArchaicFP
Definition MCFloat.h:359
@ kModernFP
Definition MCFloat.h:358
Boolean DoublesAreNotNearlyEqual(double n1, double n2)
Definition MCFloat.h:488
Sint32 NNAFract
Definition MCFloat.h:609
NNAFixed NNALong2Fix(Sint32 x)
Boolean Double1_LT_Double2(double n1, double n2)
Definition MCFloat.h:508
force_inline float DoubleToFloat(double dblVal)
Definition MCFloat.h:578
NNAFract NNAX2Frac(double x)
bool IsZeroOrDenormal(double v)
Definition MCFloat.h:313
EFPByteOrder
Definition MCFloat.h:351
@ kNeedsByteSwapping
Definition MCFloat.h:352
@ kNativeByteOrder
Definition MCFloat.h:353
Sint32 DoubleToLong(double x)
Definition MCFloat.h:139
bool IsInfinite(double v)
Definition MCFloat.h:301
void ByteSwapDoubleMAF(double *pld)
Definition MCFloat.h:373
Real64 double_gs
Definition MCFloat.h:35
const double kNearlyEqualEpsilonForNormalizedValues
Definition MCFloat.cpp:15
short WholeNumberDigits(double_param inValue)
Boolean Double1_GE_Double2(double n1, double n2)
Definition MCFloat.h:493
void ByteSwapDOUBLE80(extended80_gs *p)
Definition MCFloat.h:334
force_inline Boolean DoublesAreNearlyEqual(const double &n1, const double &n2, double epsilon=kNearlyEqualEpsilonForDoubles)
Definition MCFloat.h:463
Boolean NormalizedValuesAreNearlyEqual(double n1, double n2)
Definition MCFloat.h:545
Definition MCFloat.h:67
short w[5]
Definition MCFloat.h:67