diff --git a/libs/image/kis_brush_mask_applicator_factories.cpp b/libs/image/kis_brush_mask_applicator_factories.cpp index d550b200fb..27066311bd 100644 --- a/libs/image/kis_brush_mask_applicator_factories.cpp +++ b/libs/image/kis_brush_mask_applicator_factories.cpp @@ -1,515 +1,516 @@ /* * Copyright (c) 2012 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_brush_mask_applicator_factories.h" +#include "vc_extra_math.h" #include "kis_circle_mask_generator.h" #include "kis_circle_mask_generator_p.h" #include "kis_gauss_circle_mask_generator_p.h" #include "kis_curve_circle_mask_generator_p.h" #include "kis_gauss_rect_mask_generator_p.h" #include "kis_brush_mask_applicators.h" #include "kis_brush_mask_applicator_base.h" #define a(_s) #_s #define b(_s) a(_s) template<> template<> MaskApplicatorFactory::ReturnType MaskApplicatorFactory::create(ParamType maskGenerator) { return new KisBrushMaskScalarApplicator(maskGenerator); } template<> template<> MaskApplicatorFactory::ReturnType MaskApplicatorFactory::create(ParamType maskGenerator) { return new KisBrushMaskVectorApplicator(maskGenerator); } template<> template<> MaskApplicatorFactory::ReturnType MaskApplicatorFactory::create(ParamType maskGenerator) { return new KisBrushMaskVectorApplicator(maskGenerator); } template<> template<> MaskApplicatorFactory::ReturnType MaskApplicatorFactory::create(ParamType maskGenerator) { return new KisBrushMaskVectorApplicator(maskGenerator); } template<> template<> MaskApplicatorFactory::ReturnType MaskApplicatorFactory::create(ParamType maskGenerator) { return new KisBrushMaskVectorApplicator(maskGenerator); } #if defined HAVE_VC struct KisCircleMaskGenerator::FastRowProcessor { FastRowProcessor(KisCircleMaskGenerator *maskGenerator) : d(maskGenerator->d.data()) {} template void process(float* buffer, int width, float y, float cosa, float sina, float centerX, float centerY); KisCircleMaskGenerator::Private *d; }; template<> void KisCircleMaskGenerator:: FastRowProcessor::process(float* buffer, int width, float y, float cosa, float sina, float centerX, float centerY) { const bool useSmoothing = d->copyOfAntialiasEdges; const bool noFading = d->noFading; float y_ = y - centerY; float sinay_ = sina * y_; float cosay_ = cosa * y_; float* bufferPointer = buffer; Vc::float_v currentIndices = Vc::float_v::IndexesFromZero(); Vc::float_v increment((float)Vc::float_v::size()); Vc::float_v vCenterX(centerX); Vc::float_v vCosa(cosa); Vc::float_v vSina(sina); Vc::float_v vCosaY_(cosay_); Vc::float_v vSinaY_(sinay_); Vc::float_v vXCoeff(d->xcoef); Vc::float_v vYCoeff(d->ycoef); Vc::float_v vTransformedFadeX(d->transformedFadeX); Vc::float_v vTransformedFadeY(d->transformedFadeY); Vc::float_v vOne(Vc::One); for (int i=0; i < width; i+= Vc::float_v::size()){ Vc::float_v x_ = currentIndices - vCenterX; Vc::float_v xr = x_ * vCosa - vSinaY_; Vc::float_v yr = x_ * vSina + vCosaY_; Vc::float_v n = pow2(xr * vXCoeff) + pow2(yr * vYCoeff); Vc::float_m outsideMask = n > vOne; if (!outsideMask.isFull()) { if (noFading) { Vc::float_v vFade(Vc::Zero); vFade(outsideMask) = vOne; vFade.store(bufferPointer, Vc::Aligned); } else { if (useSmoothing) { xr = Vc::abs(xr) + vOne; yr = Vc::abs(yr) + vOne; } Vc::float_v vNormFade = pow2(xr * vTransformedFadeX) + pow2(yr * vTransformedFadeY); //255 * n * (normeFade - 1) / (normeFade - n) Vc::float_v vFade = n * (vNormFade - vOne) / (vNormFade - n); // Mask in the inner circe of the mask Vc::float_m mask = vNormFade < vOne; vFade.setZero(mask); // Mask out the outer circe of the mask vFade(outsideMask) = vOne; vFade.store(bufferPointer, Vc::Aligned); } } else { // Mask out everything outside the circle vOne.store(bufferPointer, Vc::Aligned); } currentIndices = currentIndices + increment; bufferPointer += Vc::float_v::size(); } } struct KisGaussCircleMaskGenerator::FastRowProcessor { FastRowProcessor(KisGaussCircleMaskGenerator *maskGenerator) : d(maskGenerator->d.data()) {} template void process(float* buffer, int width, float y, float cosa, float sina, float centerX, float centerY); KisGaussCircleMaskGenerator::Private *d; }; template<> void KisGaussCircleMaskGenerator:: FastRowProcessor::process(float* buffer, int width, float y, float cosa, float sina, float centerX, float centerY) { const bool antialiasOn = d->fadeMaker.getAliasingEnabled(); float y_ = y - centerY; float sinay_ = sina * y_; float cosay_ = cosa * y_; float* bufferPointer = buffer; Vc::float_v currentIndices = Vc::float_v::IndexesFromZero(); Vc::float_v increment((float)Vc::float_v::size()); Vc::float_v vCenterX(centerX); Vc::float_v vCenter(d->center); Vc::float_v vCosa(cosa); Vc::float_v vSina(sina); Vc::float_v vCosaY_(cosay_); Vc::float_v vSinaY_(sinay_); Vc::float_v vYCoeff(d->ycoef); Vc::float_v vDistfactor(d->distfactor); Vc::float_v vAlphafactor(d->alphafactor); Vc::float_v vFadeRadius(d->fadeMaker.getRadius()); Vc::float_v vFadeStartValue(d->fadeMaker.getFadeStartValue()); Vc::float_v vFadeAFadeStart(d->fadeMaker.getAntialiasingFadeStart()); Vc::float_v vFadeAFadeCoeff(d->fadeMaker.getAntialiasingFadeCoeff()); Vc::float_v vOne(Vc::One); Vc::float_v vZero(Vc::Zero); Vc::float_v vValMax(255.f); for (int i=0; i < width; i+= Vc::float_v::size()){ Vc::float_v x_ = currentIndices - vCenterX; Vc::float_v xr = x_ * vCosa - vSinaY_; Vc::float_v yr = x_ * vSina + vCosaY_; Vc::float_v dist = sqrt(pow2(xr) + pow2(yr * vYCoeff)); // BEGIN FadeMaker needFade vectorized // follow fademaker rules for outsideMask Vc::float_m outsideMask = dist > vFadeRadius; dist(outsideMask) = vOne; Vc::float_m fadeStartMask(false); // if antialias is off, do not process if(antialiasOn){ fadeStartMask = dist > vFadeAFadeStart; dist((outsideMask ^ fadeStartMask) & fadeStartMask) = (vFadeStartValue + (dist - vFadeAFadeStart) * vFadeAFadeCoeff) / vValMax; } Vc::float_m excludeMask(outsideMask | fadeStartMask); if (!excludeMask.isFull()) { Vc::float_v valDist = dist * vDistfactor; - Vc::float_v fullFade = vAlphafactor * ( d->vErf(valDist + vCenter) - d->vErf(valDist - vCenter)); + Vc::float_v fullFade = vAlphafactor * ( VcExtraMath::erf(valDist + vCenter) - VcExtraMath::erf(valDist - vCenter)); Vc::float_m mask; // Mask undefined values, out of range are out of mask mask = Vc::isfinite(fullFade); fullFade.setZero(!mask); // Mask in the inner circe of the mask mask = fullFade < vZero; fullFade.setZero(mask); // Mask the outter circle mask = fullFade > 254.974f; fullFade(mask) = vValMax; // Mask (value - value), presicion errors. Vc::float_v vFade = (vValMax - fullFade) / vValMax; // return original dist values before vFade transform vFade(excludeMask) = dist; vFade.store(bufferPointer, Vc::Aligned); } else { dist.store(bufferPointer, Vc::Aligned); } currentIndices = currentIndices + increment; bufferPointer += Vc::float_v::size(); } } struct KisCurveCircleMaskGenerator::FastRowProcessor { FastRowProcessor(KisCurveCircleMaskGenerator *maskGenerator) : d(maskGenerator->d.data()) {} template void process(float* buffer, int width, float y, float cosa, float sina, float centerX, float centerY); KisCurveCircleMaskGenerator::Private *d; }; template<> void KisCurveCircleMaskGenerator:: FastRowProcessor::process(float* buffer, int width, float y, float cosa, float sina, float centerX, float centerY) { const bool antialiasOn = d->fadeMaker.getAliasingEnabled(); float y_ = y - centerY; float sinay_ = sina * y_; float cosay_ = cosa * y_; float* bufferPointer = buffer; qreal* curveDataPointer = d->curveData.data(); Vc::float_v currentIndices = Vc::float_v::IndexesFromZero(); Vc::float_v increment((float)Vc::float_v::size()); Vc::float_v vCenterX(centerX); Vc::float_v vCosa(cosa); Vc::float_v vSina(sina); Vc::float_v vCosaY_(cosay_); Vc::float_v vSinaY_(sinay_); Vc::float_v vYCoeff(d->ycoef); Vc::float_v vXCoeff(d->xcoef); Vc::float_v vCurveResolution(d->curveResolution); Vc::float_v vCurvedData(Vc::Zero); Vc::float_v vCurvedData1(Vc::Zero); Vc::float_v vFadeRadius(d->fadeMaker.getRadius()); Vc::float_v vFadeStartValue(d->fadeMaker.getFadeStartValue()); Vc::float_v vFadeAFadeStart(d->fadeMaker.getAntialiasingFadeStart()); Vc::float_v vFadeAFadeCoeff(d->fadeMaker.getAntialiasingFadeCoeff()); Vc::float_v vOne(Vc::One); Vc::float_v vZero(Vc::Zero); Vc::float_v vValMax(255.f); for (int i=0; i < width; i+= Vc::float_v::size()){ Vc::float_v x_ = currentIndices - vCenterX; Vc::float_v xr = x_ * vCosa - vSinaY_; Vc::float_v yr = x_ * vSina + vCosaY_; Vc::float_v dist = pow2(xr * vXCoeff) + pow2(yr * vYCoeff); // BEGIN FadeMaker needFade vectorized // follow fademaker rules for outsideMask Vc::float_m outsideMask = dist > vFadeRadius; dist(outsideMask) = vOne; Vc::float_m fadeStartMask(false); // if antialias is off, do not process if(antialiasOn){ fadeStartMask = dist > vFadeAFadeStart; dist((outsideMask ^ fadeStartMask) & fadeStartMask) = (vFadeStartValue + (dist - vFadeAFadeStart) * vFadeAFadeCoeff) / vValMax; } Vc::float_m excludeMask = outsideMask | fadeStartMask; if (!excludeMask.isFull()) { Vc::float_v valDist = dist * vCurveResolution; // truncate Vc::SimdArray vAlphaValue(valDist); Vc::float_v vFloatAlphaValue = vAlphaValue; Vc::float_v alphaValueF = valDist - vFloatAlphaValue; vCurvedData.gather(curveDataPointer,vAlphaValue); vCurvedData1.gather(curveDataPointer,vAlphaValue + 1); // Vc::float_v vCurvedData1(curveDataPointer,vAlphaValue + 1); // vAlpha Vc::float_v fullFade = ( (vOne - alphaValueF) * vCurvedData + alphaValueF * vCurvedData1); Vc::float_m mask; // Mask in the inner circe of the mask mask = fullFade < vZero; fullFade.setZero(mask); // Mask outer circle of mask mask = fullFade >= vOne; Vc::float_v vFade = (vOne - fullFade); vFade.setZero(mask); // return original dist values before vFade transform vFade(excludeMask) = dist; vFade.store(bufferPointer, Vc::Aligned); } else { dist.store(bufferPointer, Vc::Aligned); } currentIndices = currentIndices + increment; bufferPointer += Vc::float_v::size(); } } struct KisGaussRectangleMaskGenerator::FastRowProcessor { FastRowProcessor(KisGaussRectangleMaskGenerator *maskGenerator) : d(maskGenerator->d.data()) {} template void process(float* buffer, int width, float y, float cosa, float sina, float centerX, float centerY); KisGaussRectangleMaskGenerator::Private *d; }; template<> void KisGaussRectangleMaskGenerator:: FastRowProcessor::process(float* buffer, int width, float y, float cosa, float sina, float centerX, float centerY) { const bool antialiasOn = d->fadeMaker.getAliasingEnabled(); float y_ = y - centerY; float sinay_ = sina * y_; float cosay_ = cosa * y_; float* bufferPointer = buffer; Vc::float_v currentIndices = Vc::float_v::IndexesFromZero(); Vc::float_v increment((float)Vc::float_v::size()); Vc::float_v vCenterX(centerX); Vc::float_v vCosa(cosa); Vc::float_v vSina(sina); Vc::float_v vCosaY_(cosay_); Vc::float_v vSinaY_(sinay_); Vc::float_v vhalfWidth(d->halfWidth); Vc::float_v vhalfHeight(d->halfHeight); Vc::float_v vXFade(d->xfade); Vc::float_v vYFade(d->yfade); Vc::float_v vAlphafactor(d->alphafactor); Vc::float_v vXLimit(d->fadeMaker.getXLimit()); Vc::float_v vYLimit(d->fadeMaker.getYLimit()); Vc::float_v vXFadeLimitStart(d->fadeMaker.getXFadeLimitStart()); Vc::float_v vYFadeLimitStart(d->fadeMaker.getYFadeLimitStart()); Vc::float_v vXFadeCoeff(d->fadeMaker.getXFadeCoeff()); Vc::float_v vYFadeCoeff(d->fadeMaker.getYFadeCoeff()); Vc::float_v vOne(Vc::One); Vc::float_v vZero(Vc::Zero); Vc::float_v vValMax(255.f); for (int i=0; i < width; i+= Vc::float_v::size()){ Vc::float_v x_ = currentIndices - vCenterX; Vc::float_v xr = x_ * vCosa - vSinaY_; Vc::float_v yr = abs(x_ * vSina + vCosaY_); Vc::float_v vValue; // BEGIN FadeMaker needFade vectorized 2D Vc::float_v xra = abs(xr); Vc::float_m outXMask = xr > vXLimit; Vc::float_m outYMask = yr > vYLimit; Vc::float_m excludeMask(outXMask | outYMask); vValue(excludeMask) = vOne; if (!excludeMask.isFull()) { - Vc::float_v fullFade = vValMax - (vAlphafactor * (d->vErf((vhalfWidth + xr) * vXFade) + d->vErf((vhalfWidth - xr) * vXFade)) - * (d->vErf((vhalfHeight + yr) * vYFade) + d->vErf((vhalfHeight - yr) * vYFade))); + Vc::float_v fullFade = vValMax - (vAlphafactor * (VcExtraMath::erf((vhalfWidth + xr) * vXFade) + VcExtraMath::erf((vhalfWidth - xr) * vXFade)) + * (VcExtraMath::erf((vhalfHeight + yr) * vYFade) + VcExtraMath::erf((vhalfHeight - yr) * vYFade))); // if antialias is off, do not process Vc::float_m fadeXStartMask(false); Vc::float_m fadeYStartMask(false); if(antialiasOn){ Vc::float_v fadeValue; Vc::SimdArray vBaseValue(fullFade); fadeXStartMask = xra > vXFadeLimitStart; fadeXStartMask = (fadeXStartMask ^ excludeMask) & fadeXStartMask; if (!fadeXStartMask.isFull()) { fadeValue = vBaseValue + (vValMax - vBaseValue) * (xra - vXFadeLimitStart) * vXFadeCoeff; fadeValue(fadeXStartMask & ((yr > vYFadeLimitStart) & (fadeValue < vValMax)) ) = fadeValue + (vValMax - fadeValue) * (yr - vYFadeLimitStart) * vYFadeCoeff; fullFade(fadeXStartMask) = fadeValue; } fadeYStartMask = yr > vYFadeLimitStart; fadeYStartMask = (fadeYStartMask ^ fadeXStartMask) & fadeYStartMask; if (!fadeYStartMask.isFull()) { fadeValue = vBaseValue + (vValMax - vBaseValue) * (yr - vYFadeLimitStart) * vYFadeCoeff; fadeValue(fadeYStartMask & ((xra > vXFadeLimitStart) & (fadeValue < vValMax)) ) = fadeValue + (vValMax - fadeValue) * (xra - vXFadeLimitStart) * vXFadeCoeff; fullFade(fadeYStartMask) = fadeValue; } } Vc::float_m mask; // Mask undefined values, out of range are out of mask mask = Vc::isfinite(fullFade); fullFade.setZero(!mask); // Mask in the inner circe of the mask mask = fullFade < vZero; fullFade.setZero(mask); // Mask the outter circle mask = fullFade > 254.974f; fullFade(mask) = vValMax; // Mask (value - value), presicion errors. Vc::float_v vFade = fullFade / vValMax; // return original vValue values before vFade transform vFade(excludeMask) = vValue; vFade.store(bufferPointer, Vc::Aligned); } else { vValue.store(bufferPointer, Vc::Aligned); } currentIndices = currentIndices + increment; bufferPointer += Vc::float_v::size(); } } #endif /* defined HAVE_VC */ diff --git a/libs/image/kis_gauss_circle_mask_generator_p.h b/libs/image/kis_gauss_circle_mask_generator_p.h index ff139f5039..f2e74586af 100644 --- a/libs/image/kis_gauss_circle_mask_generator_p.h +++ b/libs/image/kis_gauss_circle_mask_generator_p.h @@ -1,79 +1,55 @@ /* * Copyright (c) 2008-2009 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_GAUSS_MASK_GENERATOR_P_H_ #define _KIS_GAUSS_MASK_GENERATOR_P_H_ #include "kis_antialiasing_fade_maker.h" #include "kis_brush_mask_applicator_base.h" struct Q_DECL_HIDDEN KisGaussCircleMaskGenerator::Private { Private(bool enableAntialiasing) : fadeMaker(*this, enableAntialiasing) { } Private(const Private &rhs) : ycoef(rhs.ycoef), fade(rhs.fade), center(rhs.center), distfactor(rhs.distfactor), alphafactor(rhs.alphafactor), fadeMaker(rhs.fadeMaker, *this) { } qreal ycoef; qreal fade; qreal center; qreal distfactor; qreal alphafactor; KisAntialiasingFadeMaker1D fadeMaker; QScopedPointer applicator; inline quint8 value(qreal dist) const; - #if defined HAVE_VC - // vectorized erf function, precision 1e-5 - Vc::float_v vErf(Vc::float_v x) { - Vc::float_v xa = abs(x); - Vc::float_m precisionLimit(xa >= 9.3f); // wrong result for any number beyond this - xa(precisionLimit) = 0; - Vc::float_v sign(Vc::One); - Vc::float_m invertMask = x < 0.f; - sign(invertMask) = -1.f; - - // CONSTANTS - float a1 = 0.254829592; - float a2 = -0.284496736; - float a3 = 1.421413741; - float a4 = -1.453152027; - float a5 = 1.061405429; - float p = 0.3275911; - - Vc::float_v t = 1.0f / (1.0f + p * xa); - Vc::float_v y = 1.0f - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * exp(-xa * xa); - y(precisionLimit) = 1.0f; - return sign * y; - } - #endif /* defined HAVE_VC */ }; #endif /* _KIS_GAUSS_MASK_GENERATOR_P_H_ */ diff --git a/libs/image/kis_gauss_rect_mask_generator_p.h b/libs/image/kis_gauss_rect_mask_generator_p.h index c72c21185f..326202253e 100644 --- a/libs/image/kis_gauss_rect_mask_generator_p.h +++ b/libs/image/kis_gauss_rect_mask_generator_p.h @@ -1,81 +1,57 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2011 Geoffry Song * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_GAUSS_RECT_MASK_GENERATOR_P_H #define KIS_GAUSS_RECT_MASK_GENERATOR_P_H #include #include "kis_antialiasing_fade_maker.h" #include "kis_brush_mask_applicator_base.h" struct Q_DECL_HIDDEN KisGaussRectangleMaskGenerator::Private { Private(bool enableAntialiasing) : fadeMaker(*this, enableAntialiasing) { } Private(const Private &rhs) : xfade(rhs.xfade), yfade(rhs.yfade), halfWidth(rhs.halfWidth), halfHeight(rhs.halfHeight), alphafactor(rhs.alphafactor), fadeMaker(rhs.fadeMaker, *this) { } qreal xfade, yfade; qreal halfWidth, halfHeight; qreal alphafactor; KisAntialiasingFadeMaker2D fadeMaker; QScopedPointer applicator; inline quint8 value(qreal x, qreal y) const; - #if defined HAVE_VC - // vectorized erf function, precision 1e-5 - Vc::float_v vErf(Vc::float_v x) { - Vc::float_v xa = abs(x); - Vc::float_m precisionLimit(xa >= 9.3f); // wrong result for any number beyond this - xa(precisionLimit) = 0; - Vc::float_v sign(Vc::One); - Vc::float_m invertMask = x < 0.f; - sign(invertMask) = -1.f; - - // CONSTANTS - float a1 = 0.254829592; - float a2 = -0.284496736; - float a3 = 1.421413741; - float a4 = -1.453152027; - float a5 = 1.061405429; - float p = 0.3275911; - - Vc::float_v t = 1.0f / (1.0f + p * xa); - Vc::float_v y = 1.0f - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * exp(-xa * xa); - y(precisionLimit) = 1.0f; - return sign * y; - } - #endif /* defined HAVE_VC */ }; #endif // KIS_GAUSS_RECT_MASK_GENERATOR_P_H diff --git a/libs/image/vc_extra_math.h b/libs/image/vc_extra_math.h new file mode 100644 index 0000000000..42fbfa52ec --- /dev/null +++ b/libs/image/vc_extra_math.h @@ -0,0 +1,40 @@ +#ifndef VC_ADDITIONAL_MATH_H +#define VC_ADDITIONAL_MATH_H + +#include + +#if defined HAVE_VC + +#include +#include + +class VcExtraMath +{ +public: + // vectorized erf function, precision 1e-5 + static inline Vc::float_v erf(Vc::float_v x) { + Vc::float_v xa = abs(x); + Vc::float_m precisionLimit(xa >= 9.3f); // wrong result for any number beyond this + xa(precisionLimit) = 0; + Vc::float_v sign(Vc::One); + Vc::float_m invertMask = x < 0.f; + sign(invertMask) = -1.f; + + // CONSTANTS + float a1 = 0.254829592; + float a2 = -0.284496736; + float a3 = 1.421413741; + float a4 = -1.453152027; + float a5 = 1.061405429; + float p = 0.3275911; + + Vc::float_v t = 1.0f / (1.0f + p * xa); + Vc::float_v y = 1.0f - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * exp(-xa * xa); + y(precisionLimit) = 1.0f; + return sign * y; + } +}; +#endif /* defined HAVE_VC */ + + +#endif // VC_ADDITIONAL_MATH_H