/**************************************************************************** ** ** This file is part of GAP, a system for computational discrete algebra. ** ** Copyright of GAP belongs to its developers, whose names are too numerous ** to list here. Please refer to the COPYRIGHT file for details. ** ** SPDX-License-Identifier: GPL-2.0-or-later ** ** This file contains integer related functions which are independent of the ** large integer representation in use. See integer.c for other things.
*/
/**************************************************************************** ** ** * * * * * * * "Mersenne twister" random numbers * * * * * * * * * * * * * ** ** Part of this code for fast generation of 32 bit pseudo random numbers with ** a period of length 2^19937-1 and a 623-dimensional equidistribution is ** taken from: ** http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html ** (Also look in Wikipedia for "Mersenne twister".) ** We use the file mt19937ar.c, version 2002/1/26.
*/
/**************************************************************************** ** *F InitRandomMT( <initstr> ) ** ** Returns a string that can be used as data structure of a new MT random ** number generator. <initstr> can be an arbitrary string as seed.
*/ #define MATRIX_A 0x9908b0dfUL // constant vector a #define UPPER_MASK 0x80000000UL // most significant w-r bits #define LOWER_MASK 0x7fffffffUL // least significant r bits
staticvoid initGRMT(UInt4 * mt, UInt4 s)
{
UInt4 mti;
mt[0]= s & 0xffffffffUL; for (mti=1; mti<624; mti++) {
mt[mti] =
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
mt[mti] &= 0xffffffffUL;
} // store mti as last entry of mt[]
mt[624] = mti;
}
// Read s[pos], returning 0 if pos is past the error of the array staticinline UChar checkedReadChar(const UChar * s, UInt4 pos, UInt4 len)
{ if (pos < len) return s[pos]; else return 0;
}
// to read a seed string independently of endianness staticinline UInt4 uint4frombytes(const UChar * s, UInt4 pos, UInt4 len)
{
UInt4 res;
res = checkedReadChar(s, pos + 3, len);
res <<= 8;
res += checkedReadChar(s, pos + 2, len);
res <<= 8;
res += checkedReadChar(s, pos + 1, len);
res <<= 8;
res += checkedReadChar(s, pos + 0, len); return res;
}
// check the seed, given as string
RequireStringRep(SELF_NAME, initstr);
/* store array of 624 UInt4 and one UInt4 as counter "mti" and an
endianness marker */
str = NEW_STRING(4*626);
SET_LEN_STRING(str, 4*626);
mt = (UInt4 *)(ADDR_OBJ(str) + 1); // here the counter mti is set to 624
initGRMT(mt, 19650218UL);
i=1; j=0; // Do not set these up until all garbage collection is done
init_key = CONST_CHARS_STRING(initstr);
byte_key_length = GET_LEN_STRING(initstr);
key_length = byte_key_length / 4;
k = (N>key_length ? N : key_length); for (; k; k--) {
mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1664525UL)) +
uint4frombytes(init_key, 4 * j, byte_key_length) + j;
mt[i] &= 0xffffffffUL;
i++; j++; if (i>=N) { mt[0] = mt[N-1]; i=1; } if (4 * j >= byte_key_length) j=0;
} for (k=N-1; k; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) - i;
mt[i] &= 0xffffffffUL;
i++; if (i>=N) { mt[0] = mt[N-1]; i=1; }
}
mt[0] = 0x80000000UL; // gives string "1234" in little endian as marker
mt[625] = 875770417UL; return str;
}
/* internal, generates a random number on [0,0xffffffff]-interval ** argument <mt> is pointer to a string generated by InitRandomMT ** (the first 4*624 bytes are the random numbers, the last 4 bytes contain ** a counter)
*/
UInt4 nextrandMT_int32(UInt4* mt)
{
UInt4 mti, y, N=624, M=397; static UInt4 mag01[2]={0x0UL, MATRIX_A};
mti = mt[624]; if (mti >= N) { int kk;
for (kk=0;kk<N-M;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
} for (;kk<N-1;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
mti = 0;
}
y = mt[mti++];
mt[624] = mti;
// Tempering
y ^= (y >> 11);
y ^= (y << 7) & 0x9d2c5680UL;
y ^= (y << 15) & 0xefc60000UL;
y ^= (y >> 18);
return y;
}
//----------------------------------------------------------------------------- // MurmurHash3 was written by Austin Appleby, and is placed in the public // domain. The author hereby disclaims copyright to this source code.
// Note - The x86 and x64 versions do _not_ produce the same results, as the // algorithms are optimized for their respective platforms. You can still // compile and run any of them on any platform, but your performance with the // non-native version will be less than optimal.
//----------------------------------------------------------------------------- // MurmurHash3 was written by Austin Appleby, and is placed in the public // domain. The author hereby disclaims copyright to this source code.
/* Minor modifications to get it to compile in C rather than C++ and
integrate with GAP SL*/
#define FORCE_INLINE staticinline
#ifndef SYS_IS_64_BIT
//----------------------------------------------------------------------------- // Platform-specific functions and macros
//----------------------------------------------------------------------------- // Block read - if your platform needs to do endian-swapping or can only // handle aligned reads, do the conversion here
FORCE_INLINE uint32_t getblock4 ( const uint32_t * p, int i )
{ return p[i];
}
//----------------------------------------------------------------------------- // Finalization mix - force all bits of a hash block to avalanche
FORCE_INLINE uint32_t fmix4 ( uint32_t h )
{
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
//----------------------------------------------------------------------------- // Block read - if your platform needs to do endian-swapping or can only // handle aligned reads, do the conversion here // // The pointer p may not be aligned, which means that directly reading it can // incur a major performance penalty or even trigger a segfault on certain // architectures (e.g. ARM, SPARC). Thus we use memcpy here, with the implicit // hope that on archs which don't need this, the compiler will optimize it back // into a direct copy (verified to happen with GCC and clang on x86_64)
FORCE_INLINE uint64_t getblock8 ( const uint64_t * p, int i )
{
uint64_t val;
memcpy(&val, p + i, sizeof(uint64_t)); return val;
}
//----------------------------------------------------------------------------- // Finalization mix - force all bits of a hash block to avalanche
FORCE_INLINE uint64_t fmix8 ( uint64_t k )
{
k ^= k >> 33;
k *= BIG_CONSTANT(0xff51afd7ed558ccd);
k ^= k >> 33;
k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
k ^= k >> 33;
/**************************************************************************** ** *F FuncHASHKEY_BAG(<self>,<obj>,<seed>,<offset>,<maxlen>) ** ** 'FuncHASHKEY_BAG' implements the internal function 'HASHKEY_BAG'. ** ** 'HASHKEY_BAG( <obj>, <seed>, <offset>, <maxlen> )' ** ** takes a non-immediate object and a small integer <seed> and computes a ** hash value for the contents of the bag from these. For this to be usable ** in algorithms, we need that objects of this kind are stored uniquely ** internally. ** The offset and the maximum number of bytes to process both count in ** bytes. The values passed to these parameters might depend on the word ** length of the computer. ** A <maxlen> value of -1 indicates infinity.
*/ static Obj
FuncHASHKEY_BAG(Obj self, Obj obj, Obj seed, Obj offset, Obj maxlen)
{ Int n; if ( IS_INTOBJ(obj) ) return obj;
if ( IS_FFE(obj) ) { /* We must be careful here, as different FFEs can represent equal values (e.g. 0*Z(2^2) and 0*Z(2) compare as equal). Thus, we cannot simply use the bit pattern of obj to compute a hash, as a well-defined hash function must satisfy the implication obj1 = obj2 => HASH(obj1) = HASH(obj2) There are different ways to do this for FFEs, with different trade-offs. Instead of making an arbitrary choice here, let's just refuse to compute a hash here, and require the caller to provide a custom hash function tailored to their needs.
*/
ErrorMayQuit("HASHKEY_BAG: must not be an FFE", 0, 0);
}
// check the arguments Int s = GetSmallInt(SELF_NAME, seed);
Int offs = GetSmallInt(SELF_NAME, offset); if (offs < 0 || offs > SIZE_OBJ(obj)) {
ErrorMayQuit("HashKeyBag: must be non-negative and less than " "the bag size",
0, 0);
}
// maximal number of bytes to read Int imaxlen = GetSmallInt(SELF_NAME, maxlen);
n=SIZE_OBJ(obj)-offs;
if (n > imaxlen && imaxlen != -1) {
n = imaxlen;
}
/**************************************************************************** ** *F SmallInt Bitfield operations ** ** The goal here it to set up a division of the usable bits in a small ** integer into fields which can be accessed very quickly from GAP level and ** quickly and conveniently from C. The purpose is to allow implementation ** of data structures that divide up the bits within a word without having ** to make them entirely opaque to the GAP level or ridiculously slow. ** ** The API is defined in lib/bitfields.gd and works by providing the user ** with a collection of functions to get and set fields and assemble an ** entire word. ** ** These functions are constructed here and have special handlers. The ** information the handlers need about the size and position of the ** bitfields are stored in special fields added after the regular function ** bag fields, and are referred to as MASK_BITFIELD_FUNC and ** OFFSET_BITFIELD_FUNC. ** ** For fields of size 1 we also offer Boolean setters and getters which ** accept and return True for 1 and False for 0. This makes for much nicer ** code on the GAP side.
*/ typedefstruct {
FuncBag f;
static Obj DoBooleanFieldSetter(Obj self, Obj data, Obj val)
{
UInt x = GetSmallInt("Boolean Field Setter", data);
RequireTrueOrFalse("Boolean Field Setter", val);
UInt mask = MASK_BITFIELD_FUNC(self); if (val == True)
x |= mask; elseif (val == False)
x &= ~mask; return INTOBJ_INT(x);
}
static Obj FuncBUILD_BITFIELDS(Obj self, Obj args)
{
GAP_ASSERT(IS_PLIST(args));
GAP_ASSERT(LEN_PLIST(args) >= 1 && ELM_PLIST(args, 1));
Obj widths = ELM_PLIST(args, 1);
RequireSmallList(SELF_NAME, widths);
UInt nfields = LEN_LIST(widths); if (LEN_PLIST(args) != nfields + 1)
ErrorMayQuit( "Fields builder: number of values must match number of widths", 0,
0);
UInt x = 0;
UInt i; for (i = nfields; i > 0; i--) {
GAP_ASSERT(ISB_LIST(widths, i));
Obj y = ELM_LIST(widths, i);
x <<= INT_INTOBJ(y);
GAP_ASSERT(ELM_PLIST(args, i + 1));
Obj z = ELM_PLIST(args, i + 1); if (!IS_NONNEG_INTOBJ(z))
ErrorMayQuit("Fields builder: values must be non-negative small integers", 0,
0);
GAP_ASSERT(INT_INTOBJ(z) < (1 << INT_INTOBJ(y)));
x |= INT_INTOBJ(z);
} return INTOBJ_INT(x);
}
static Obj FuncMAKE_BITFIELDS(Obj self, Obj widths)
{
RequireSmallList(SELF_NAME, widths);
UInt nfields = LEN_LIST(widths);
UInt starts[nfields + 1];
starts[0] = 0; for (UInt i = 1; i <= nfields; i++) {
Obj o = ELM_LIST(widths, i); if (!IS_NONNEG_INTOBJ(o))
ErrorMayQuit("MAKE_BITFIELDS: widths must be non-negative small integers", 0,
0);
UInt width = INT_INTOBJ(o);
starts[i] = starts[i - 1] + width;
} if (starts[nfields] > 8 * sizeof(UInt))
ErrorMayQuit("MAKE_BITFIELDS: total widths too large", 0, 0);
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.34Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.