我应该如何在软件中实现通用 FMA/FMAF 指令?

2024-06-21

FMA是一个融合乘加指令。这fmaf (float x, float y, float z)函数于glibc称为vfmadd213ss操作说明。我想知道这个指令是如何执行的。据我的理解:

  1. 添加的指数x and y .
  2. 尾数相乘x and y.
  3. 将结果归一化x * y,但不是四舍五入。
  4. 比较的指数z并移动较小指数的尾数
  5. 添加尾数,结果再次归一化
  6. rounded(rn).

当前的 x86-64 架构实现了所谓的 FMA3 变体:由于融合乘加运算需要三个源操作数,如果实现它的指令总共只有三个操作数,则必须指定哪个源操作数也是目标:vfmadd123ss, vfmadd213ss, vfmadd231ss.

就数学功能而言,这些指令都是等效的,并通过单次舍入计算 a*b+c,其中 a、b 和 c 是 IEEE-754binary32(单精度)操作数,在 C 和 C++ 系列编程语言中通常映射到float.

问题中提供的顶级算法大纲是正确的。下面的代码演示了如何在 IEEE-754 浮点异常关闭(即代码提供 IEEE-754 标准规定的屏蔽响应)和次正常支持打开的限制下实现所有必要的细节(许多平台,包括 x86-64,也支持非标准的“清零”和“非正规数为零”模式)。当向 FMA 提供多个 NaN 源操作数时,其中任何一个或规范的 NaN 都会构成结果的基础。在下面的代码中,我简单地匹配了我的工作站中的 Xeon W2133 CPU 的行为;其他处理器可能需要调整。

下面的代码是普通的 FMA 仿真,其编码具有合理的性能和合理的清晰度。如果平台提供 CLZ(计算前导零)或相关指令,那么通过内在函数进行接口将会很有帮助。正确的舍入很大程度上取决于舍入位和粘性位的正确跟踪。在硬件中,这些通常是两个实际位,但对于软件仿真来说,使用整个无符号整数通常很有用(rndstk在下面的代码中),其中最高有效位代表轮位,所有剩余的低位位集体(即“或”在一起)代表粘性位。

实用(更快)fmaf()仿真一通常依赖于在 IEEE-754 中执行中间计算binary64(双精度)。这会产生棘手的双舍入问题,并且并非常见开源库中的所有实现都能正常工作。从文献中已知的最好方法是在中间计算中使用特殊的舍入模式,舍入到奇数。看:

Sylvie Boldo 和 Guillaume Melquiond,“FMA 的仿真和正确舍入总和:使用舍入到奇数的证明算法”IEEE 计算机汇刊,卷。 57,第 4 期,2008 年 2 月,第 462-471 页。

严格测试 FMA 实现(无论是硬件还是软件)都是一个难题。由于搜索空间巨大,简单地使用大量(例如数百亿)随机测试向量将仅提供“冒烟”测试,这对于证明实现并未无可救药地被破坏很有用。下面我添加了基于模式的测试,这些测试能够执行许多极端情况。尽管如此,下面的代码应该只被考虑轻微测试.

如果您打算以任何专业身份使用 FMA 仿真,我强烈建议您投入大量时间来确保功能正确性;坦率地说,已经有太多损坏的 FMA 仿真了。对于工业强度的实施,hardware供应商采用经过机械检查的数学证明来证明操作正确。这本书由一位拥有丰富经验的从业者编写,很好地概述了其在实践中的运作方式:

大卫·M·鲁西诺夫,浮点设计的形式验证:数学方法,施普林格2019。

还有专业的测试套件用于练习许多极端情况,例如FPgen 浮点测试生成器 https://researcher.watson.ibm.com/researcher/view_group.php?id=9517来自海法 IBM 研究实验室。他们曾经在他们的网站上免费提供一系列单精度测试向量,但我似乎再也找不到它们了。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <limits.h>
#include <math.h>

#define PURELY_RANDOM  (0)
#define PATTERN_BASED  (1)
#define TEST_MODE      (PURELY_RANDOM)
#define ROUND_MODE     (roundNearest) 

/* vvvvvvvvvvvvvvvvvvvvvvvvvvv x86-64 specific vvvvvvvvvvvvvvvvvvvvvvvvvvvv */
#include "immintrin.h"

#define roundMinInf  (_MM_ROUND_DOWN)
#define roundPosInf  (_MM_ROUND_UP)
#define roundZero    (_MM_ROUND_TOWARD_ZERO)
#define roundNearest (_MM_ROUND_NEAREST)

#define ftzOff       (_MM_FLUSH_ZERO_OFF)
#define dazOff       (_MM_DENORMALS_ZERO_OFF)

void set_subnormal_support (uint32_t ftz, uint32_t daz)
{
    _MM_SET_DENORMALS_ZERO_MODE (ftz);
    _MM_SET_FLUSH_ZERO_MODE (daz);
}

float ref_fmaf (float a, float b, float c, uint32_t rnd)
{
    __m128 r, s, t, u;
    float res;
    uint32_t old_mxcsr;
    old_mxcsr = _mm_getcsr();
    _MM_SET_ROUNDING_MODE (rnd);
    s = _mm_set_ss (a);
    t = _mm_set_ss (b);
    u = _mm_set_ss (c);
    r = _mm_fmadd_ss (s, t, u);
    _mm_store_ss (&res, r);
    _mm_setcsr (old_mxcsr);
    return res;
}
/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^ x86-64 specific ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */

/* re-interpret bits of IEEE-754 'binary32' as unsigned 32-bit integer */
uint32_t float_as_uint32 (float a)
{
    uint32_t r;
    memcpy (&r, &a, sizeof r);
    return r;
}
/* re-interpret bits of unsigned 32-bit integer as IEEE-754 'binary32' */
float uint32_as_float (uint32_t a)
{
    float r;
    memcpy (&r, &a, sizeof r);
    return r;
}

/* 32-bit leading zero count. Use platform-specific intrinsic if available */
int clz32 (uint32_t a)
{
    int n = 32;
    if (a >= 0x00010000u) { a >>= 16;  n -= 16; }
    if (a >= 0x00000100u) { a >>=  8;  n -=  8; }
    if (a >= 0x00000010u) { a >>=  4;  n -=  4; }
    if (a >= 0x00000004u) { a >>=  2;  n -=  2; }
    n -= a & ~(a >> 1);
    return n;
}

/* 64-bit leading zero count. Use platform-specific intrinsic if available */
int clz64 (uint64_t a)
{
    uint32_t hi = (uint32_t)(a >> 32);
    uint32_t lo = (uint32_t)(a & 0xffffffff);
    return hi ? clz32 (hi) : (32 + clz32 (lo));
}

/* full product of two 32-bit unsigned integers. May use platform intrinsic */
uint64_t mul_u32_wide (uint32_t a, uint32_t b)
{
    return (uint64_t)a * b;
}

uint32_t fmaf_kernel (uint32_t x, uint32_t y, uint32_t z, int mode)     
 {     
     const uint32_t FP32_SIGN_BIT = 0x80000000;
     const uint32_t FP32_POS_ZERO = 0x00000000;
     const uint32_t FP32_NEG_ZERO = 0x80000000;
     const uint32_t FP32_QNAN_BIT = 0x00400000;
     const uint32_t FP32_INT_BIT  = 0x00800000;
     const uint32_t FP32_EXPO_MASK = 0x7f800000;
     const uint32_t FP32_POS_INFINITY = 0x7f800000;
     const uint32_t FP32_NEG_INFINITY = 0xff800000;
     const uint32_t FP32_POS_MAX_NORMAL = 0x7f7fffff;
     const uint32_t FP32_NEG_MAX_NORMAL = 0xff7fffff;
     const uint32_t FP32_QNAN_INDEFINITE = 0xffc00000;
     const uint32_t FP32_EXPO_BIAS = 127;
     const uint32_t FP32_STORED_MANT_BITS = 23;
     const uint32_t FP32_EXPO_BITS = 8;
     const uint32_t FP32_MAX_NORM_EXPO_M1 = 254 - 1;
     uint64_t mant_p, templl;
     uint32_t mant_x, mant_y, mant_z, mant_r;
     uint32_t expo_x, expo_y, expo_z, expo_r, expo_p;
     uint32_t sign_z, sign_p, sign_r;
     uint32_t r, shift, lz, rndstk, z_zer, temp;
      
     expo_x = ((x & FP32_EXPO_MASK) >> FP32_STORED_MANT_BITS) - 1;
     expo_y = ((y & FP32_EXPO_MASK) >> FP32_STORED_MANT_BITS) - 1;
     expo_z = ((z & FP32_EXPO_MASK) >> FP32_STORED_MANT_BITS) - 1;
     z_zer = (z << 1) == 0x00000000;
      
     if (!((expo_x <= FP32_MAX_NORM_EXPO_M1) &&
           (expo_y <= FP32_MAX_NORM_EXPO_M1) &&
           (expo_z <= FP32_MAX_NORM_EXPO_M1))) {
         uint32_t x_nan = (x << 1) >  0xff000000;
         uint32_t y_nan = (y << 1) >  0xff000000;
         uint32_t z_nan = (z << 1) >  0xff000000;
         uint32_t x_inf = (x << 1) == 0xff000000;
         uint32_t y_inf = (y << 1) == 0xff000000;
         uint32_t z_inf = (z << 1) == 0xff000000;
         uint32_t x_zer = (x << 1) == 0x00000000;
         uint32_t y_zer = (y << 1) == 0x00000000;
         
         /* pass-through quietened NaN arguments */
         if (y_nan) {
             return y | FP32_QNAN_BIT;
         }
         if (x_nan) {
             return x | FP32_QNAN_BIT;
         }
         if (z_nan) {
             return z | FP32_QNAN_BIT;
         }
         /* invalid operations, bsed on zeros and infinities */
         if (((x_zer && y_inf) || (y_zer && x_inf)) ||
             (z_inf && (x_inf || y_inf) && ((int32_t)(x ^ y ^ z) < 0))) {
             return FP32_QNAN_INDEFINITE;
         }
         /* infinity results */
         if (x_inf) {
             return x ^ (y & FP32_SIGN_BIT);
         }
         if (y_inf) {
             return y ^ (x & FP32_SIGN_BIT);
         }
         if (z_inf) {
             return z;
         }
         /* results of negative zero */
         if ((z == FP32_NEG_ZERO) &&
             (x_zer || y_zer) && ((int32_t)(x ^ y) < 0)) {
             return z;
         }
         /* zero results */
         if (z_zer && (x_zer || y_zer)) {
             return ((mode == roundMinInf) ?
                     ((x ^ y ^ z) & FP32_SIGN_BIT) : (z & ~FP32_SIGN_BIT));
         }
         /* product x*y is zero: pass-through z */
         if (x_zer || y_zer) {
             return z;
         }
         /* normalize x if subnormal */
         if (expo_x == (uint32_t)-1) {    
             temp = x << FP32_EXPO_BITS;
             lz = clz32 (temp);
             temp = temp << lz;
             expo_x = expo_x - lz + 1;
             x = (temp >> FP32_EXPO_BITS) | (x & FP32_SIGN_BIT);
         }
         /* normalize y if subnormal */
         if (expo_y == (uint32_t)-1) {
             temp = y << FP32_EXPO_BITS;
             lz = clz32 (temp);
             temp = temp << lz;
             expo_y = expo_y - lz + 1;
             y = (temp >> FP32_EXPO_BITS) | (y & FP32_SIGN_BIT);
         }
         /* normalize z if subnormal */
         if ((expo_z == (uint32_t)-1) && (!z_zer)) {
             temp = z << FP32_EXPO_BITS;
             lz = clz32 (temp);
             temp = temp << lz;
             expo_z = expo_z - lz + 1;
             z = (temp >> FP32_EXPO_BITS) | (z & FP32_SIGN_BIT);
         }
     }

     /* multiply x * y */
     expo_p = expo_x + expo_y - FP32_EXPO_BIAS + 2;
     sign_p = (x ^ y) & FP32_SIGN_BIT;
     mant_x = (x & 0x00ffffff) | FP32_INT_BIT;
     mant_y = (y << 8) | (FP32_INT_BIT << 8);
     mant_p = mul_u32_wide (mant_x, mant_y);
     
     /* normalize product x*y */
     if (!(mant_p & ((uint64_t)FP32_INT_BIT << 32))) {
         mant_p = mant_p << 1;
         expo_p--;
     }

     /* add z to produxt x*y */
     if (z_zer) {
         expo_r = expo_p;
         sign_r = sign_p;
         mant_r = (uint32_t)(mant_p >> 32);
         rndstk = (uint32_t)(mant_p);
     } else {
         sign_z = z & FP32_SIGN_BIT;
         mant_z = (z & 0x00ffffff) | FP32_INT_BIT;
         uint64_t large, small, mant_z_ext = (uint64_t)mant_z << 32;
         /* sort summands by magnitude of significands */
         if (((int)expo_p > (int)expo_z) ||
             ((expo_p == expo_z) && (mant_p > mant_z_ext))) {
             expo_r = expo_p;
             sign_r = sign_p;
             large = mant_p;
             small = mant_z_ext;
             shift = expo_p - expo_z;
         } else {
             expo_r = expo_z;
             sign_r = sign_z;
             large = mant_z_ext;
             small = mant_p;
             shift = expo_z - expo_p;
         }
         /* denormalize small */
         if (shift == 0) {
             rndstk = 0;
         } else if (shift > 63) {
             rndstk = 1; // only sticky
             small = 0;
         } else {
             templl = small << (64 - shift);
             rndstk = (uint32_t)(templl >> 32) | (((uint32_t)templl) ? 1 : 0);
             small = small >> shift;
         }
         /* add or subtract significants */
         if (sign_p != sign_z) {
             large = large - small - (rndstk ? 1 : 0);
             /* complete cancelation: return 0 */
             if (large == 0) {
                 return (mode == roundMinInf) ? FP32_NEG_ZERO : FP32_POS_ZERO;
             }
             /* normalize mantissa if necessary */
             if (!(large & ((uint64_t)FP32_INT_BIT << 32))) {
                 lz = clz64 (large);
                 shift = lz - 8;
                 large = large << shift;
                 expo_r = expo_r - shift;
             }
         } else {
             large = large + small;
             /* normalize mantissa if necessary */
             if (large & 0x0100000000000000ULL) {
                 templl = large << 63;
                 rndstk = (uint32_t)(templl >> 32) | (rndstk ? 1 : 0);
                 large = large >> 1;
                 expo_r++;
             }
         }
         mant_r = (uint32_t)(large >> 32);
         rndstk = (uint32_t)(large) | (rndstk ? 1 : 0);
     }

     /* round result */
     if (expo_r <= FP32_MAX_NORM_EXPO_M1) { // normal
         if (mode == roundNearest) {
             mant_r += (rndstk == 0x80000000) ? (mant_r & 1) : (rndstk >> 31);
         } else if (mode == roundPosInf) {
             mant_r += rndstk && !sign_r;
         } else if (mode == roundMinInf) {
             mant_r += rndstk && sign_r;
         } else { // mode == roundZero
         }
         r = sign_r + mant_r + (expo_r << 23);
         return r;
     } else if ((int32_t)expo_r >= 0) { // overflow: largest normal or infinity
         if (mode == roundNearest) {
             r = sign_r | FP32_POS_INFINITY;
         } else if (mode == roundZero) {
             r = sign_r | FP32_POS_MAX_NORMAL;
         } else if (mode == roundPosInf) {
             r = sign_r ? FP32_NEG_MAX_NORMAL : FP32_POS_INFINITY;
         } else { // (mode == roundMinInf)
             r = sign_r ? FP32_NEG_INFINITY : FP32_POS_MAX_NORMAL;
         }
         return r;
     } else { /* underflow: smallest normal, subnormal, or zero */
         shift = 0 - expo_r;
         rndstk = (shift > 25) ? 1 : ((mant_r << (32 - shift)) | (rndstk ? 1 : 0));
         mant_r = (shift > 25) ? 0 : (mant_r >> shift);
         if (mode == roundNearest) {
             mant_r += ((rndstk == 0x80000000) ? (mant_r & 1) : (rndstk >> 31));
         } else if (mode == roundPosInf) {
             mant_r += rndstk && !sign_r;
         } else if (mode == roundMinInf) {
             mant_r += rndstk && sign_r;
         } else { // mode == roundZero
         }
         r = sign_r + mant_r;
     }

     return r;
}     

float my_fmaf (float a, float b, float c, uint32_t rnd)
{
    return uint32_as_float (fmaf_kernel (float_as_uint32 (a),
                                         float_as_uint32 (b),
                                         float_as_uint32 (c),
                                         rnd));
}   

uint32_t v[8192];
// George Marsaglia's KISS PRNG, period 2**123. Newsgroup sci.math, 21 Jan 1999
// Bug fix: Greg Rose, "KISS: A Bit Too Simple" http://eprint.iacr.org/2011/007
static uint32_t kiss_z=362436069, kiss_w=521288629;
static uint32_t kiss_jsr=123456789, kiss_jcong=380116160;
#define znew (kiss_z=36969*(kiss_z&65535)+(kiss_z>>16))
#define wnew (kiss_w=18000*(kiss_w&65535)+(kiss_w>>16))
#define MWC  ((znew<<16)+wnew )
#define SHR3 (kiss_jsr^=(kiss_jsr<<13),kiss_jsr^=(kiss_jsr>>17), \
              kiss_jsr^=(kiss_jsr<<5))
#define CONG (kiss_jcong=69069*kiss_jcong+1234567)
#define KISS ((MWC^CONG)+SHR3)

int main (void)
{
    const uint32_t rnd = ROUND_MODE;
    unsigned long long count = 0;
    float a, b, c, res, ref;
    const uint32_t nbrBits = sizeof (uint32_t) * CHAR_BIT;
    uint32_t i, j, patterns, idx = 0;
    uint32_t ai, bi, ci, resi, refi;

    /* pattern class 1: 2**i */
    for (i = 0; i < nbrBits; i++) {
        v [idx] = ((uint32_t)1 << i);
        idx++;
    }
    /* pattern class 2: 2**i-1 */
    for (i = 0; i < nbrBits; i++) {
        v [idx] = (((uint32_t)1 << i) - 1);
        idx++;
    }
    /* pattern class 3: 2**i+1 */
    for (i = 0; i < nbrBits; i++) {
        v [idx] = (((uint32_t)1 << i) + 1);
        idx++;
    }
    /* pattern class 4: 2**i + 2**j */
    for (i = 0; i < nbrBits; i++) {
        for (j = 0; j < nbrBits; j++) {
            v [idx] = (((uint32_t)1 << i) + ((uint32_t)1 << j));
            idx++;
        }
    }
    /* pattern class 5: 2**i - 2**j */
    for (i = 0; i < nbrBits; i++) {
        for (j = 0; j < nbrBits; j++) {
            v [idx] = (((uint32_t)1 << i) - ((uint32_t)1 << j));
            idx++;
        }
    }
    /* pattern class 6: MAX_UINT/(2**i+1) rep. blocks of i zeros an i ones */
    for (i = 0; i < nbrBits; i++) {
        v [idx] = ((~(uint32_t)0) / (((uint32_t)1 << i) + 1));
        idx++;
    }
    patterns = idx;
    /* pattern class 6: one's complement of pattern classes 1 through 5 */
    for (i = 0; i < patterns; i++) {
        v [idx] = ~v [i];
        idx++;
    }
    /* pattern class 7: two's complement of pattern classes 1 through 5 */
    for (i = 0; i < patterns; i++) {
        v [idx] = ~v [i] + 1;
        idx++;
    }
    patterns = idx;

    printf ("testing single-precision FMA\n");
    printf ("rounding mode: ");
    if (rnd == roundZero) {
        printf ("toward zero (truncate)\n");
    } else if (rnd == roundNearest) {
        printf ("round to nearest, ties to even\n");
    } else if (rnd == roundPosInf) {
        printf ("round up (toward positive infinity)\n");
    } else if (rnd == roundMinInf) {
        printf ("round down (toward negative infinity)\n");
    } else {
        printf ("unsupported\n");
        return EXIT_FAILURE;
    }

#if TEST_MODE == PURELY_RANDOM
    printf ("using purely random test vectors\n");
#elif TEST_MODE == PATTERN_BASED
    printf ("using pattern-based test vectors\n");
    printf ("#patterns = %u\n", patterns);
#endif // TEST_MODE

    /* make sure subnormal support is turned on */
    set_subnormal_support (ftzOff, dazOff);

    do {
#if TEST_MODE == PURELY_RANDOM
        ai = KISS;
        bi = KISS;
        ci = KISS;
#elif TEST_MODE == PATTERN_BASED
        ai = KISS;
        bi = KISS;
        ci = KISS;
        ai = ((v[ai%patterns] & 0x7fffff) | (KISS & ~0x7fffff));
        bi = ((v[bi%patterns] & 0x7fffff) | (KISS & ~0x7fffff));
        ci = ((v[ci%patterns] & 0x7fffff) | (KISS & ~0x7fffff));
#endif // TEST_MODE
        a = uint32_as_float (ai);
        b = uint32_as_float (bi);
        c = uint32_as_float (ci);
        res = my_fmaf (a, b, c, rnd);
        ref = ref_fmaf (a, b, c, rnd);
        resi = float_as_uint32 (res);
        refi = float_as_uint32 (ref);
        if (!(resi == refi)) {
            printf ("!!!! error @ a=%08x (% 15.8e)  b=%08x (% 15.8e)  c=%08x (% 15.8e)  res = %08x (% 15.8e)  ref = %08x (% 15.8e)\n",
                    ai, a, bi, b, ci, c, resi, res, refi, ref);
            return EXIT_FAILURE;
        }
        count++;
        if (!(count & 0xffffff)) printf ("\r%llu", count);
    } while (1);
    return EXIT_SUCCESS;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我应该如何在软件中实现通用 FMA/FMAF 指令? 的相关文章

  • 计算二维笛卡尔坐标中不规则形状的边界

    我正在寻找一种计算不规则形状边界的解决方案 Lats take a look at Square example 如果我有Minimum x and y and Maximum x and y like MaxX 5 MinX 1 MaxY
  • 如何求两个地点的经纬度距离?

    我有一组位置的纬度和经度 怎么找distance从集合中的一个位置到另一个位置 有公式吗 半正矢公式假定地球是球形的 然而 地球的形状更为复杂 扁球体模型会给出更好的结果 如果需要这样的精度 你应该更好地使用文森特逆公式 See http
  • 用于评估数组单调性的算法(即判断数组的“排序性”)

    EDIT 哇 很多很棒的回复 是的 我使用它作为适应度函数来判断遗传算法执行的排序的质量 因此 评估成本很重要 即 它必须是快速的 最好是O n 作为我正在使用的人工智能应用程序的一部分 我希望能够根据候选整数数组的单调性 也称为 排序性
  • 我可以使用 AVX FMA 单元进行位精确的 52 位整数乘法吗?

    AXV2 doesn t have any integer multiplications with sources larger than 32 bit It does offer 32 x 32 gt 32 http www felix
  • 为什么编译时浮点计算可能不会得到与运行时计算相同的结果?

    In the speaker mentioned Compile time floating point calculations might not have the same results as runtime calculation
  • 浮点运算的最佳实践

    我正在对精确到小数点后第二位的小数输入执行加法和减法 我试图通过乘以 100 将它们转换为整数来提高准确性 但效果却相反 考虑以下代码和输出 double d 2 01 int a int d 100 0 cout lt lt a lt l
  • 使用 FIND 命令进行并集、交集和排除?

    我需要使用 find 命令管理列表 假设列表在非不同列表中具有随机名称 即它们的交集不是空集 我能怎么做 A B 查找列表A中除列表B中的文件之外的文件 A 路口 B 查找列表 A 和 B 共有的文件 请咨询here https stack
  • .NET 中严格浮点数学的库

    我有 Java 算法 计算及其单元测试 单元测试期望结果具有一定的精度 增量 现在我将算法移植到 NET 中 并希望使用相同的单元测试 我使用双数据类型 问题在于 Java 使用 strictfp 64 位 来执行 Math 类中的某些操作
  • 我应该如何在软件中实现通用 FMA/FMAF 指令?

    FMA是一个融合乘加指令 这fmaf float x float y float z 函数于glibc称为vfmadd213ss操作说明 我想知道这个指令是如何执行的 据我的理解 添加的指数x and y 尾数相乘x and y 将结果归一
  • 如何计算圆圆周上点的(x或y)坐标?

    px and py是圆圆周上一点的 x 和 y 坐标 Given the center of the circle as cx cy the radius of the circle as r px 如何计算 的值py 谢谢 给定 px p
  • 将 1970 年以来的秒数转换为日期的数学,反之亦然

    我自 1970 年 1 月 1 日 00 00 以来的秒数为 int64 以纳秒为单位 我正在尝试将其转换为月 日 年 星期几 迭代地执行此操作很容易 我可以做到这一点 但我想以公式化的方式执行此操作 我正在寻找实际的数学 老问题的新答案
  • 在 C++ 中返回浮点数组

    我目前有一个 C 中的 4x4 矩阵类 并将每个值存储为浮点数 Matrix4d Matrix4d const float m00 const float m01 const float m02 const float m03 const
  • Python 中浮点数到分数的转换

    在对 Python 3 52 中的 float 类型到 Fraction 类型转换主题进行练习时 我发现了两种不同转换方式之间的差异 第一种方法是 gt gt gt from fractions import Fraction gt gt
  • 在 WIN32 与 WIN64 中配置浮点单元上下文

    我正在尝试编写一个未处理的异常过滤器 请参阅 SetUnhandledExceptionFilter 以与 Windows SEH 一起使用来报告无效的浮点操作 我想捕获异常 打印堆栈跟踪 然后禁用浮点异常并使用生成的非有限或非数字值恢复执
  • 计算序列 1,3,8,22,60,164,448,1224... 的第 n 项? [复制]

    这个问题在这里已经有答案了 可能的重复 我想以 Order 1 或 nlogn 的顺序生成序列 1 3 8 22 60 164 的第 n 项 https stackoverflow com questions 11301992 i want
  • Python数学域错误[重复]

    这个问题在这里已经有答案了 我正在编写一个程序来求解二次方程并打印根 在进入主程序之前 我只是想求平方根 我收到的错误是 数学域错误 如果有人能给我一些帮助来解释为什么它不起作用 那就太好了 import math a int sys ar
  • 任意旋转中两条抛物线相交的代码或公式

    我正在研究一个几何问题 需要找到任何旋转中两个抛物线弧的交点 我能够通过旋转平面使弧与轴对齐来相交直线和抛物线弧 但两条抛物线不能同时与轴对齐 我正在努力推导公 式 但我想知道是否有可用的资源 我首先定义没有旋转的二维抛物线弧的方程 x t
  • 如何确定 n 高数字金字塔中的最大路线成本

    我有一个像这样的数字金字塔 7 4 8 1 8 9 2 4 6 7 4 6 7 4 9 4 9 7 3 8 8 routes 32 每个数字都按其系列中的强大程度进行索引 0 9 gt 1 1 8 gt 5 2 8 gt 4 3 7 gt
  • Haskell 乘加运算的数学性能

    我正在用 Haskell 编写一个游戏 我当前在 UI 上的传递涉及大量几何图形的程序生成 我目前专注于识别一项特定操作的性能 C ish 伪代码 Vec4f multiplier addend Vec4f vecList for int
  • 快速找到一个数字的下一个倍数的方法

    我需要找到从基数开始的数字的第一个倍数 例如 7 中 3 的第一个倍数是 9 我的第一次尝试是这样做 multiple baseNumber while multiple number 0 multiple 最后 multiple 将具有第

随机推荐