/*
  This is a test for floating point constants.

  How to compile for DOS (huge/.EXE, unreal/.EXE, 32-bit DPMI/.EXE):
    smlrcc -dosh fpconst.c -o fpconsth.exe
    smlrcc -dosu fpconst.c -o fpconstu.exe
    smlrcc -dosp fpconst.c -o fpconstp.exe

  How to compile for Windows:
    smlrcc -win fpconst.c -o fpconstw.exe

  How to compile for Linux:
    smlrcc -linux fpconst.c -o fpconstl

  How to compile for MacOS:
    smlrcc -macos fpconst.c -o fpconstm
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// Make sure float and int are the same size, so they can be
// copied one into another byte by byte with memcpy().
extern char StAtIcAsSeRt[(sizeof(float) == sizeof(unsigned)) ? 1 : -1];

#define TEST_ENTRY(U,F)  { U, #F, F##f }

struct
{
  unsigned AsUint;
  const char* Decimal;
  float Flt;
} const testData[] =
{
  TEST_ENTRY(0x00000000,00.),
  TEST_ENTRY(0x00000000,.00),
  TEST_ENTRY(0x00000000,00.00),
  TEST_ENTRY(0x3F800000,10e-1),
  TEST_ENTRY(0x3F800000,.1e1),
  TEST_ENTRY(0x3F800000,.01e2),
  TEST_ENTRY(0x3F800000,00.00100e3),
  TEST_ENTRY(0x41400000,12.),
  TEST_ENTRY(0x3DF5C28F,.12),
  TEST_ENTRY(0x3DF5C28F,+.12),
  TEST_ENTRY(0xBDF5C28F,-.12),
  TEST_ENTRY(0x414570A4,12.34),
  TEST_ENTRY(0x414570A4,+12.34),
  TEST_ENTRY(0xC14570A4,-12.34),
  TEST_ENTRY(0x3DCCCCCD,00.100),
  TEST_ENTRY(0x42C80000,00100.),
  TEST_ENTRY(0x42C80083,00100.00100),
  TEST_ENTRY(0x461C4000,1e4),
  TEST_ENTRY(0x3F000000,0.5),
  TEST_ENTRY(0x3F19999A,0.6),
  TEST_ENTRY(0x3E800000,0.25),
  TEST_ENTRY(0x3E851EB8,0.26),
  TEST_ENTRY(0x3E000000,0.125),
  TEST_ENTRY(0x3E010625,0.126),
  TEST_ENTRY(0x3D800000,0.0625),
  TEST_ENTRY(0x3D7F9724,0.0624),
  TEST_ENTRY(0x3D000000,0.03125),
  TEST_ENTRY(0x3CFFEB07,0.03124),
  TEST_ENTRY(0x65A96816,1e23),
  TEST_ENTRY(0x19416D9A,1E-23),
  TEST_ENTRY(0x65A96816,1e+23),
  TEST_ENTRY(0x7F800000,12.34E56),
  TEST_ENTRY(0x7F800000,+12.34E+56),
  TEST_ENTRY(0x80000000,-12.34e-56),
  TEST_ENTRY(0x766CA884,+.12E+34),
  TEST_ENTRY(0x857F3637,-.12e-34),
  TEST_ENTRY(0x7F7FFFFF,3.4028234e38),
  TEST_ENTRY(0x7F7FFFFF,3.4028235e38),
  TEST_ENTRY(0x7F800000,3.4028236e38),
  TEST_ENTRY(0x7F800000,1.7976931348623158e308),
  TEST_ENTRY(0x7F800000,1.7976931348623159e308),
  TEST_ENTRY(0x7F800000,1e1000),
  TEST_ENTRY(0xFF800000,-1.7976931348623158e308),
  TEST_ENTRY(0xFF800000,-1.7976931348623159e308),
  TEST_ENTRY(0x00000000,2.2250738585072014e-308),
  TEST_ENTRY(0x00000000,2.2250738585072013e-308),
  TEST_ENTRY(0x00000000,2.2250738585072012e-308),
  TEST_ENTRY(0x00000000,2.2250738585072011e-308),
  TEST_ENTRY(0x00000000,4.9406564584124654e-324),
  TEST_ENTRY(0x00000000,2.4703282292062328e-324),
  TEST_ENTRY(0x00000000,2.4703282292062327e-324),
  TEST_ENTRY(0x80000000,-4.9406564584124654e-325),
  TEST_ENTRY(0x00000000,1e-1000),
  TEST_ENTRY(0x00000000,1.00431469722921494e-140),
  TEST_ENTRY(0x4B076543,8873283.0),
  TEST_ENTRY(0x37000000,0.00000762939453125),
  TEST_ENTRY(0x00800000,0.000000000000000000000000000000000000011754943508222875079687365372222456778186655567720875215087517062784172594547271728515625), // min normalized float
  TEST_ENTRY(0x007FFFFF,0.00000000000000000000000000000000000001175494210692441075487029444849287348827052428745893333857174530571588870475618904265502351336181163787841796875), // max denormalized float
  TEST_ENTRY(0x00000001,0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125), // min denormalized float
  TEST_ENTRY(0x00800000,11754943508222875079687365372222456778186655567720875215087517062784172594547271728515625e-126), // min normalized float
  TEST_ENTRY(0x007FFFFF,1175494210692441075487029444849287348827052428745893333857174530571588870475618904265502351336181163787841796875e-149), // max denormalized float
  TEST_ENTRY(0x00000001,140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125e-149), // min denormalized float
  TEST_ENTRY(0x7F7FFFFF,340282346638528859811704183484516925440.), // max float
  TEST_ENTRY(0x00000001,1e-45),
  TEST_ENTRY(0x00000001,9.9999999e-46),
  TEST_ENTRY(0x00000001,8e-46),
  TEST_ENTRY(0x00000000,7e-46),

  // Extra test data from Vern Paxson's paper
  // "A Program for Testing IEEE DecimalBinary Conversion"
  TEST_ENTRY(0x1F6C1E4A,5e-20                     ),
  TEST_ENTRY(0x59BE6CEA,67e+14                    ),
  TEST_ENTRY(0x5D5AB6C4,985e+15                   ),
  TEST_ENTRY(0x0053C4F4,7693e-42                  ),
  TEST_ENTRY(0x2CC4A9BD,55895e-16                 ),
  TEST_ENTRY(0x006C85C4,996622e-44                ),
  TEST_ENTRY(0x15AE43FD,7038531e-32               ),
  TEST_ENTRY(0x0041CA76,60419369e-46              ),
  TEST_ENTRY(0x2CF757CA,702990899e-20             ),
  TEST_ENTRY(0x004B7678,6930161142e-48            ),
  TEST_ENTRY(0x665BA998,25933168707e+13           ),
  TEST_ENTRY(0x743C3324,596428896559e+20          ),
  TEST_ENTRY(0x1A111234,3e-23                     ),
  TEST_ENTRY(0x6045C22C,57e+18                    ),
  TEST_ENTRY(0x0A23DE70,789e-35                   ),
  TEST_ENTRY(0x2736F449,2539e-18                  ),
  TEST_ENTRY(0x7616398A,76173e+28                 ),
  TEST_ENTRY(0x3714F05C,887745e-11                ),
  TEST_ENTRY(0x0D2EACA7,5382571e-37               ),
  TEST_ENTRY(0x128289D1,82381273e-35              ),
  TEST_ENTRY(0x0F18377E,750486563e-38             ),
  TEST_ENTRY(0x0E98377E,3752432815e-39            ),
  TEST_ENTRY(0x06C7FB32,75224575729e-45           ),
  TEST_ENTRY(0x6BBE38A0,459926601011e+15          ),
  TEST_ENTRY(0x140AA638,7e-27                     ),
  TEST_ENTRY(0x11EA83EF,37e-29                    ),
  TEST_ENTRY(0x265627B9,743e-18                   ),
  TEST_ENTRY(0x0F1F70A5,7861e-33                  ),
  TEST_ENTRY(0x15642477,46073e-30                 ),
  TEST_ENTRY(0x10C45BBB,774497e-34                ),
  TEST_ENTRY(0x14221C69,8184513e-33               ),
  TEST_ENTRY(0x1E29B508,89842219e-28              ),
  TEST_ENTRY(0x1DA9B508,449211095e-29             ),
  TEST_ENTRY(0x0D83E630,8128913627e-40            ),
  TEST_ENTRY(0x33BB9DC9,87365670181e-18           ),
  TEST_ENTRY(0x333B9DC9,436828350905e-19          ),
  TEST_ENTRY(0x033D88B2,5569902441849e-49         ),
  TEST_ENTRY(0x213163BF,60101945175297e-32        ),
  TEST_ENTRY(0x0380524D,754205928904091e-51       ),
  TEST_ENTRY(0x1C3340CC,5930988018823113e-37      ),
  TEST_ENTRY(0x2E6222EA,51417459976130695e-27     ),
  TEST_ENTRY(0x191FD0AA,826224659167966417e-41    ),
  TEST_ENTRY(0x0068AC8E,9612793100620708287e-57   ),
  TEST_ENTRY(0x1FDC1BC2,93219542812847969081e-39  ),
  TEST_ENTRY(0x122C9581,544579064588249633923e-48 ),
  TEST_ENTRY(0x13C57CF8,4985301935905831716201e-48),
  TEST_ENTRY(0x6C3A1D9A,9e+26                     ),
  TEST_ENTRY(0x35541063,79e-8                     ),
  TEST_ENTRY(0x6EFDF865,393e+26                   ),
  TEST_ENTRY(0x039C0957,9171e-40                  ),
  TEST_ENTRY(0x2CC5EFCD,56257e-16                 ),
  TEST_ENTRY(0x2C45EFCD,281285e-17                ),
  TEST_ENTRY(0x031FA15C,4691113e-43               ),
  TEST_ENTRY(0x3300D2D0,29994057e-15              ),
  TEST_ENTRY(0x01E32F8D,834548641e-46             ),
  TEST_ENTRY(0x00734821,1058695771e-47            ),
  TEST_ENTRY(0x33BB9DC9,87365670181e-18           ),
  TEST_ENTRY(0x1787067C,872580695561e-36          ),
  TEST_ENTRY(0x00484836,6638060417081e-51         ),
  TEST_ENTRY(0x006056E2,88473759402752e-52        ),
  TEST_ENTRY(0x2AE82B19,412413848938563e-27       ),
  TEST_ENTRY(0x09E84998,5592117679628511e-48      ),
  TEST_ENTRY(0x088B5F5B,83881765194427665e-50     ),
  TEST_ENTRY(0x22EB9D2B,638632866154697279e-35    ),
  TEST_ENTRY(0x0640B59C,3624461315401357483e-53   ),
  TEST_ENTRY(0x2EA6C146,75831386216699428651e-30  ),
  TEST_ENTRY(0x1BD79427,356645068918103229683e-42 ),
  TEST_ENTRY(0x2CF71813,7022835002724438581513e-33),
};

int main(void)
{
  unsigned i, errCnt;
  for (errCnt = i = 0; i < sizeof(testData) / sizeof(testData[0]); i++)
  {
    unsigned u, err;
    memcpy(&u, &testData[i].Flt, sizeof u);
    err = u != testData[i].AsUint;
    printf("0x%08X %c= 0x%08X == %s\n",
           u,
           "=!"[err],
           testData[i].AsUint,
           testData[i].Decimal);
    errCnt += err;
  }
  printf("%u errors\n", errCnt);
  return errCnt ? EXIT_FAILURE : EXIT_SUCCESS;
}
