コンテンツにスキップ

Go/float32

出典: フリー教科書『ウィキブックス(Wikibooks)』
< Go

Goのfloat32について

[編集]

Goにおけるfloat32は32ビット浮動小数点型を表す事前宣言された型です。IEEE 754標準に準拠した単精度浮動小数点数で、4バイトのサイズを持ち、約3.4×10^38から約3.4×10^-38までの値を表現できます。

基本情報

[編集]
  • float32は32ビット(4バイト)の単精度浮動小数点型
  • IEEE 754標準に準拠
  • 値の範囲: 約±3.4×10^38 (最大値), 約±1.2×10^-38 (最小値)
  • 精度: 約7桁の有効数字
  • メモリ上での表現: 1ビット(符号)+ 8ビット(指数)+ 23ビット(仮数)
  • 科学技術計算、グラフィクス、ゲーム開発、シミュレーションなどに使用される

他のキーワードとの組み合わせ

[編集]

変数宣言との組み合わせ

[編集]
var temperature float32 = 25.5 // 温度
var velocity float32 = 9.8     // 速度
price := float32(199.99)       // 型推論による短縮形
pi := float32(3.14159265359)   // 円周率(単精度)

// 特殊値
var infinity float32 = 1.0 / 0.0     // +Inf
var negInfinity float32 = -1.0 / 0.0 // -Inf
var notANumber float32 = 0.0 / 0.0   // NaN

定数定義との組み合わせ

[編集]
const GRAVITY float32 = 9.80665      // 重力加速度 (m/s²)
const SPEED_OF_LIGHT float32 = 2.998e8  // 光速 (m/s)
const ROOM_TEMPERATURE float32 = 20.0    // 室温 (℃)
const PI float32 = 3.14159265
const E float32 = 2.71828183

// 物理定数
const BOLTZMANN_CONSTANT float32 = 1.380649e-23 // J/K
const AVOGADRO_NUMBER float32 = 6.02214076e23   // 1/mol

関数パラメータと戻り値

[編集]
func calculateDistance(x1, y1, x2, y2 float32) float32 {
    dx := x2 - x1
    dy := y2 - y1
    return float32(math.Sqrt(float64(dx*dx + dy*dy)))
}

func celsiusToFahrenheit(celsius float32) float32 {
    return celsius*9.0/5.0 + 32.0
}

func calculateArea(radius float32) float32 {
    return PI * radius * radius
}

型変換

[編集]
i := 42
f := float32(i) // int から float32 への変換

d := 3.14159265359
f32 := float32(d) // float64 から float32 への変換(精度が落ちる可能性)

s := "3.14"
f, err := strconv.ParseFloat(s, 32) // 文字列から float32 への変換
if err == nil {
    value := float32(f)
}

// 逆変換
fValue := float32(123.456)
iValue := int(fValue)           // 小数点以下切り捨て
sValue := strconv.FormatFloat(float64(fValue), 'f', 3, 32) // 文字列化

配列とスライス

[編集]
var coordinates [3]float32           // 3D座標
var matrix [4][4]float32            // 4x4行列
var vertices []float32              // 頂点データ
temperatures := []float32{18.5, 22.3, 25.1, 19.8} // 温度記録

// OpenGLスタイルのvertexデータ
vertexData := []float32{
    // 位置(x,y,z)     テクスチャ座標(u,v)
    -0.5, -0.5, 0.0,  0.0, 0.0,
     0.5, -0.5, 0.0,  1.0, 0.0,
     0.0,  0.5, 0.0,  0.5, 1.0,
}

マップ

[編集]
stockPrices := make(map[string]float32)
stockPrices["AAPL"] = 150.25
stockPrices["GOOGL"] = 2750.80

sensorReadings := make(map[int]float32)
sensorReadings[1] = 23.5 // センサー1の温度
sensorReadings[2] = 45.8 // センサー2の湿度

構造体のフィールド

[編集]
type Vector3 struct {
    X, Y, Z float32
}

type Color struct {
    R, G, B, A float32 // RGBA値 (0.0-1.0)
}

type Weather struct {
    Temperature float32 // 温度 (℃)
    Humidity    float32 // 湿度 (%)
    Pressure    float32 // 気圧 (hPa)
    WindSpeed   float32 // 風速 (m/s)
}

type Triangle struct {
    Vertices [3]Vector3
    Color    Color
    Normal   Vector3
}

スライスとバイナリ処理

[編集]
import (
    "encoding/binary"
    "bytes"
    "unsafe"
)

// float32をバイト列に変換
func Float32ToBytes(f float32) []byte {
    buf := new(bytes.Buffer)
    binary.Write(buf, binary.LittleEndian, f)
    return buf.Bytes()
}

// バイト列からfloat32に変換
func BytesToFloat32(b []byte) float32 {
    return math.Float32frombits(binary.LittleEndian.Uint32(b))
}

// float32スライスを効率的にバイト列に変換
func Float32SliceToBytes(floats []float32) []byte {
    const sizeOfFloat32 = 4
    byteSlice := make([]byte, len(floats)*sizeOfFloat32)
    
    for i, f := range floats {
        binary.LittleEndian.PutUint32(
            byteSlice[i*sizeOfFloat32:], 
            math.Float32bits(f),
        )
    }
    return byteSlice
}

一般的なユースケース

[編集]
  1. 3Dグラフィクスと数学演算
       import "math"
       
       type Matrix4 [16]float32 // 4x4行列(列優先)
       
       func NewIdentityMatrix() Matrix4 {
           return Matrix4{
               1, 0, 0, 0,
               0, 1, 0, 0,
               0, 0, 1, 0,
               0, 0, 0, 1,
           }
       }
       
       func (m Matrix4) Multiply(other Matrix4) Matrix4 {
           var result Matrix4
           for i := 0; i < 4; i++ {
               for j := 0; j < 4; j++ {
                   for k := 0; k < 4; k++ {
                       result[i*4+j] += m[i*4+k] * other[k*4+j]
                   }
               }
           }
           return result
       }
       
       func CreateRotationMatrix(angle float32, axis Vector3) Matrix4 {
           c := float32(math.Cos(float64(angle)))
           s := float32(math.Sin(float64(angle)))
           
           // 軸を正規化
           length := float32(math.Sqrt(float64(axis.X*axis.X + axis.Y*axis.Y + axis.Z*axis.Z)))
           x, y, z := axis.X/length, axis.Y/length, axis.Z/length
           
           return Matrix4{
               c+x*x*(1-c),   x*y*(1-c)-z*s, x*z*(1-c)+y*s, 0,
               y*x*(1-c)+z*s, c+y*y*(1-c),   y*z*(1-c)-x*s, 0,
               z*x*(1-c)-y*s, z*y*(1-c)+x*s, c+z*z*(1-c),   0,
               0,             0,             0,             1,
           }
       }
       
       func CreatePerspectiveMatrix(fov, aspect, near, far float32) Matrix4 {
           f := float32(1.0 / math.Tan(float64(fov)/2.0))
           
           return Matrix4{
               f/aspect, 0, 0,                            0,
               0,        f, 0,                            0,
               0,        0, (far+near)/(near-far),        (2*far*near)/(near-far),
               0,        0, -1,                           0,
           }
       }
       
       // ベクトル演算
       func (v Vector3) Dot(other Vector3) float32 {
           return v.X*other.X + v.Y*other.Y + v.Z*other.Z
       }
       
       func (v Vector3) Cross(other Vector3) Vector3 {
           return Vector3{
               X: v.Y*other.Z - v.Z*other.Y,
               Y: v.Z*other.X - v.X*other.Z,
               Z: v.X*other.Y - v.Y*other.X,
           }
       }
       
       func (v Vector3) Length() float32 {
           return float32(math.Sqrt(float64(v.X*v.X + v.Y*v.Y + v.Z*v.Z)))
       }
       
       func (v Vector3) Normalize() Vector3 {
           length := v.Length()
           if length == 0 {
               return Vector3{0, 0, 0}
           }
           return Vector3{v.X / length, v.Y / length, v.Z / length}
       }
    
  2. 物理シミュレーション
       type Particle struct {
           Position Vector3
           Velocity Vector3
           Mass     float32
           Force    Vector3
       }
       
       type PhysicsWorld struct {
           Particles  []Particle
           Gravity    Vector3
           Damping    float32
           TimeStep   float32
       }
       
       func NewPhysicsWorld() *PhysicsWorld {
           return &PhysicsWorld{
               Particles: make([]Particle, 0),
               Gravity:   Vector3{0, -9.81, 0},
               Damping:   0.999,
               TimeStep:  1.0 / 60.0, // 60 FPS
           }
       }
       
       func (pw *PhysicsWorld) AddParticle(position Vector3, mass float32) {
           particle := Particle{
               Position: position,
               Velocity: Vector3{0, 0, 0},
               Mass:     mass,
               Force:    Vector3{0, 0, 0},
           }
           pw.Particles = append(pw.Particles, particle)
       }
       
       func (pw *PhysicsWorld) Update() {
           for i := range pw.Particles {
               particle := &pw.Particles[i]
               
               // 重力を適用
               particle.Force = Vector3{
                   pw.Gravity.X * particle.Mass,
                   pw.Gravity.Y * particle.Mass,
                   pw.Gravity.Z * particle.Mass,
               }
               
               // 加速度を計算 (F = ma)
               acceleration := Vector3{
                   particle.Force.X / particle.Mass,
                   particle.Force.Y / particle.Mass,
                   particle.Force.Z / particle.Mass,
               }
               
               // 速度を更新
               particle.Velocity.X += acceleration.X * pw.TimeStep
               particle.Velocity.Y += acceleration.Y * pw.TimeStep
               particle.Velocity.Z += acceleration.Z * pw.TimeStep
               
               // 減衰を適用
               particle.Velocity.X *= pw.Damping
               particle.Velocity.Y *= pw.Damping
               particle.Velocity.Z *= pw.Damping
               
               // 位置を更新
               particle.Position.X += particle.Velocity.X * pw.TimeStep
               particle.Position.Y += particle.Velocity.Y * pw.TimeStep
               particle.Position.Z += particle.Velocity.Z * pw.TimeStep
               
               // 地面との衝突判定
               if particle.Position.Y < 0 {
                   particle.Position.Y = 0
                   particle.Velocity.Y = -particle.Velocity.Y * 0.8 // 反発係数
               }
           }
       }
       
       func (pw *PhysicsWorld) ApplyForce(particleIndex int, force Vector3) {
           if particleIndex >= 0 && particleIndex < len(pw.Particles) {
               particle := &pw.Particles[particleIndex]
               particle.Force.X += force.X
               particle.Force.Y += force.Y
               particle.Force.Z += force.Z
           }
       }
    
  3. 色操作とグラフィクス
       func (c Color) ToRGBA255() (uint8, uint8, uint8, uint8) {
           return uint8(c.R * 255), uint8(c.G * 255), uint8(c.B * 255), uint8(c.A * 255)
       }
       
       func ColorFromRGBA255(r, g, b, a uint8) Color {
           return Color{
               R: float32(r) / 255.0,
               G: float32(g) / 255.0,
               B: float32(b) / 255.0,
               A: float32(a) / 255.0,
           }
       }
       
       func (c Color) Lerp(other Color, t float32) Color {
           return Color{
               R: c.R + (other.R-c.R)*t,
               G: c.G + (other.G-c.G)*t,
               B: c.B + (other.B-c.B)*t,
               A: c.A + (other.A-c.A)*t,
           }
       }
       
       func (c Color) ToHSV() (h, s, v float32) {
           max := c.R
           if c.G > max { max = c.G }
           if c.B > max { max = c.B }
           
           min := c.R
           if c.G < min { min = c.G }
           if c.B < min { min = c.B }
           
           v = max
           delta := max - min
           
           if max == 0 {
               s = 0
           } else {
               s = delta / max
           }
           
           if delta == 0 {
               h = 0
           } else {
               switch max {
               case c.R:
                   h = (c.G - c.B) / delta
                   if c.G < c.B {
                       h += 6
                   }
               case c.G:
                   h = (c.B-c.R)/delta + 2
               case c.B:
                   h = (c.R-c.G)/delta + 4
               }
               h /= 6
           }
           
           return h, s, v
       }
       
       func ColorFromHSV(h, s, v float32) Color {
           c := v * s
           x := c * (1 - float32(math.Abs(float64(float32(math.Mod(float64(h*6), 2))-1))))
           m := v - c
           
           var r, g, b float32
           switch int(h * 6) {
           case 0: r, g, b = c, x, 0
           case 1: r, g, b = x, c, 0
           case 2: r, g, b = 0, c, x
           case 3: r, g, b = 0, x, c
           case 4: r, g, b = x, 0, c
           case 5: r, g, b = c, 0, x
           }
           
           return Color{r + m, g + m, b + m, 1.0}
       }
    
  4. 科学技術計算とデータ処理
       import (
           "math"
           "sort"
       )
       
       type DataSet struct {
           Values []float32
           Name   string
       }
       
       func NewDataSet(name string) *DataSet {
           return &DataSet{
               Values: make([]float32, 0),
               Name:   name,
           }
       }
       
       func (ds *DataSet) Add(value float32) {
           ds.Values = append(ds.Values, value)
       }
       
       func (ds *DataSet) Mean() float32 {
           if len(ds.Values) == 0 {
               return 0
           }
           var sum float32
           for _, v := range ds.Values {
               sum += v
           }
           return sum / float32(len(ds.Values))
       }
       
       func (ds *DataSet) StandardDeviation() float32 {
           mean := ds.Mean()
           var sumSquaredDiff float32
           for _, v := range ds.Values {
               diff := v - mean
               sumSquaredDiff += diff * diff
           }
           variance := sumSquaredDiff / float32(len(ds.Values))
           return float32(math.Sqrt(float64(variance)))
       }
       
       func (ds *DataSet) Median() float32 {
           if len(ds.Values) == 0 {
               return 0
           }
           
           sorted := make([]float32, len(ds.Values))
           copy(sorted, ds.Values)
           sort.Slice(sorted, func(i, j int) bool {
               return sorted[i] < sorted[j]
           })
           
           n := len(sorted)
           if n%2 == 0 {
               return (sorted[n/2-1] + sorted[n/2]) / 2
           }
           return sorted[n/2]
       }
       
       func (ds *DataSet) Min() float32 {
           if len(ds.Values) == 0 {
               return 0
           }
           min := ds.Values[0]
           for _, v := range ds.Values[1:] {
               if v < min {
                   min = v
               }
           }
           return min
       }
       
       func (ds *DataSet) Max() float32 {
           if len(ds.Values) == 0 {
               return 0
           }
           max := ds.Values[0]
           for _, v := range ds.Values[1:] {
               if v > max {
                   max = v
               }
           }
           return max
       }
       
       // フーリエ変換の基礎(DFT)
       type Complex64 struct {
           Real, Imag float32
       }
       
       func (c Complex64) Add(other Complex64) Complex64 {
           return Complex64{c.Real + other.Real, c.Imag + other.Imag}
       }
       
       func (c Complex64) Multiply(other Complex64) Complex64 {
           return Complex64{
               c.Real*other.Real - c.Imag*other.Imag,
               c.Real*other.Imag + c.Imag*other.Real,
           }
       }
       
       func DFT(input []float32) []Complex64 {
           N := len(input)
           output := make([]Complex64, N)
           
           for k := 0; k < N; k++ {
               for n := 0; n < N; n++ {
                   angle := -2 * math.Pi * float64(k) * float64(n) / float64(N)
                   cos := float32(math.Cos(angle))
                   sin := float32(math.Sin(angle))
                   
                   output[k] = output[k].Add(Complex64{
                       Real: input[n] * cos,
                       Imag: input[n] * sin,
                   })
               }
           }
           
           return output
       }
    
  5. ゲーム開発
       type Transform struct {
           Position Vector3
           Rotation Vector3 // オイラー角
           Scale    Vector3
       }
       
       type GameObject struct {
           Transform Transform
           Velocity  Vector3
           IsActive  bool
       }
       
       type Game struct {
           Objects     []GameObject
           Camera      Transform
           DeltaTime   float32
           TotalTime   float32
       }
       
       func NewGame() *Game {
           return &Game{
               Objects:   make([]GameObject, 0),
               Camera:    Transform{Position: Vector3{0, 0, 5}, Scale: Vector3{1, 1, 1}},
               DeltaTime: 1.0 / 60.0,
           }
       }
       
       func (g *Game) AddObject(position Vector3) {
           obj := GameObject{
               Transform: Transform{
                   Position: position,
                   Rotation: Vector3{0, 0, 0},
                   Scale:    Vector3{1, 1, 1},
               },
               IsActive: true,
           }
           g.Objects = append(g.Objects, obj)
       }
       
       func (g *Game) Update() {
           g.TotalTime += g.DeltaTime
           
           for i := range g.Objects {
               if !g.Objects[i].IsActive {
                   continue
               }
               
               obj := &g.Objects[i]
               
               // 物理演算:速度から位置を更新
               obj.Transform.Position.X += obj.Velocity.X * g.DeltaTime
               obj.Transform.Position.Y += obj.Velocity.Y * g.DeltaTime
               obj.Transform.Position.Z += obj.Velocity.Z * g.DeltaTime
               
               // 重力を適用
               obj.Velocity.Y -= 9.81 * g.DeltaTime
               
               // 回転
               obj.Transform.Rotation.Y += 90.0 * g.DeltaTime // 90度/秒で回転
           }
       }
       
       func (g *Game) GetViewMatrix() Matrix4 {
           // カメラのビュー行列を生成
           return CreateLookAtMatrix(
               g.Camera.Position,
               Vector3{0, 0, 0}, // 原点を見る
               Vector3{0, 1, 0}, // Y軸が上
           )
       }
       
       func CreateLookAtMatrix(eye, center, up Vector3) Matrix4 {
           f := Vector3{
               center.X - eye.X,
               center.Y - eye.Y,
               center.Z - eye.Z,
           }.Normalize()
           
           s := f.Cross(up).Normalize()
           u := s.Cross(f)
           
           return Matrix4{
               s.X, u.X, -f.X, 0,
               s.Y, u.Y, -f.Y, 0,
               s.Z, u.Z, -f.Z, 0,
               -s.Dot(eye), -u.Dot(eye), f.Dot(eye), 1,
           }
       }
    
  6. 音声処理とシンセサイザー
       import (
           "math"
           "time"
       )
       
       type AudioBuffer struct {
           Samples    []float32
           SampleRate float32
           Channels   int
       }
       
       func NewAudioBuffer(duration time.Duration, sampleRate float32, channels int) *AudioBuffer {
           sampleCount := int(float32(duration.Nanoseconds()) / 1e9 * sampleRate) * channels
           return &AudioBuffer{
               Samples:    make([]float32, sampleCount),
               SampleRate: sampleRate,
               Channels:   channels,
           }
       }
       
       func (ab *AudioBuffer) GenerateSine(frequency, amplitude, phase float32) {
           samplesPerChannel := len(ab.Samples) / ab.Channels
           for i := 0; i < samplesPerChannel; i++ {
               t := float32(i) / ab.SampleRate
               sample := amplitude * float32(math.Sin(2*math.Pi*float64(frequency)*float64(t)+float64(phase)))
               
               for ch := 0; ch < ab.Channels; ch++ {
                   ab.Samples[i*ab.Channels+ch] = sample
               }
           }
       }
       
       func (ab *AudioBuffer) GenerateSawtooth(frequency, amplitude float32) {
           samplesPerChannel := len(ab.Samples) / ab.Channels
           for i := 0; i < samplesPerChannel; i++ {
               t := float32(i) / ab.SampleRate
               // ノコギリ波: -1 から 1 への直線的変化
               phase := math.Mod(float64(frequency)*float64(t), 1.0)
               sample := amplitude * (2*float32(phase) - 1)
               
               for ch := 0; ch < ab.Channels; ch++ {
                   ab.Samples[i*ab.Channels+ch] = sample
               }
           }
       }
       
       func (ab *AudioBuffer) ApplyLowPassFilter(cutoffFreq float32) {
           samplesPerChannel := len(ab.Samples) / ab.Channels
           dt := 1.0 / ab.SampleRate
           rc := 1.0 / (2 * math.Pi * cutoffFreq)
           alpha := dt / (rc + dt)
           
           for ch := 0; ch < ab.Channels; ch++ {
               prevSample := ab.Samples[ch]
               for i := 1; i < samplesPerChannel; i++ {
                   idx := i*ab.Channels + ch
                   ab.Samples[idx] = prevSample + alpha*(ab.Samples[idx]-prevSample)
                   prevSample = ab.Samples[idx]
               }
           }
       }
       
       func (ab *AudioBuffer) ApplyReverb(roomSize, damping, wetLevel float32) {
           samplesPerChannel := len(ab.Samples) / ab.Channels
           delayTime := int(roomSize * ab.SampleRate * 0.1) // 100ms max delay
           if delayTime >= samplesPerChannel {
               delayTime = samplesPerChannel - 1
           }
           
           for ch := 0; ch < ab.Channels; ch++ {
               for i := delayTime; i < samplesPerChannel; i++ {
                   idx := i*ab.Channels + ch
                   delayIdx := (i-delayTime)*ab.Channels + ch
                   
                   delayedSample := ab.Samples[delayIdx] * damping
                   ab.Samples[idx] = ab.Samples[idx]*(1-wetLevel) + delayedSample*wetLevel
               }
           }
       }
       
       func (ab *AudioBuffer) Normalize() {
           var maxAmp float32
           for _, sample := range ab.Samples {
               if abs := float32(math.Abs(float64(sample))); abs > maxAmp {
                   maxAmp = abs
               }
           }
           
           if maxAmp > 0 {
               scale := 1.0 / maxAmp
               for i := range ab.Samples {
                   ab.Samples[i] *= scale
               }
           }
       }
    
  7. 機械学習と数値最適化
       type NeuralNetwork struct {
           InputSize   int
           HiddenSize  int
           OutputSize  int
           WeightsIH   [][]float32 // Input to Hidden weights
           WeightsHO   [][]float32 // Hidden to Output weights
           BiasHidden  []float32
           BiasOutput  []float32
           LearningRate float32
       }
       
       func NewNeuralNetwork(inputSize, hiddenSize, outputSize int) *NeuralNetwork {
           nn := &NeuralNetwork{
               InputSize:    inputSize,
               HiddenSize:   hiddenSize,
               OutputSize:   outputSize,
               WeightsIH:    make([][]float32, hiddenSize),
               WeightsHO:    make([][]float32, outputSize),
               BiasHidden:   make([]float32, hiddenSize),
               BiasOutput:   make([]float32, outputSize),
               LearningRate: 0.01,
           }
       
           // 重みを初期化
           for i := 0; i < hiddenSize; i++ {
               nn.WeightsIH[i] = make([]float32, inputSize)
               for j := 0; j < inputSize; j++ {
                   nn.WeightsIH[i][j] = float32(math.Random())*2 - 1 // -1 to 1
               }
           }
       
           for i := 0; i < outputSize; i++ {
               nn.WeightsHO[i] = make([]float32, hiddenSize)
               for j := 0; j < hiddenSize; j++ {
                   nn.WeightsHO[i][j] = float32(math.Random())*2 - 1
               }
           }
       
           return nn
       }
       
       func sigmoid(x float32) float32 {
           return 1.0 / (1.0 + float32(math.Exp(-float64(x))))
       }
       
       func sigmoidDerivative(x float32) float32 {
           return x * (1.0 - x)
       }
       
       func (nn *NeuralNetwork) FeedForward(inputs []float32) []float32 {
           // Hidden layer
           hidden := make([]float32, nn.HiddenSize)
           for i := 0; i < nn.HiddenSize; i++ {
               sum := nn.BiasHidden[i]
               for j := 0; j < nn.InputSize; j++ {
                   sum += inputs[j] * nn.WeightsIH[i][j]
               }
               hidden[i] = sigmoid(sum)
           }
           
           // Output layer
           outputs := make([]float32, nn.OutputSize)
           for i := 0; i < nn.OutputSize; i++ {
               sum := nn.BiasOutput[i]
               for j := 0; j < nn.HiddenSize; j++ {
                   sum += hidden[j] * nn.WeightsHO[i][j]
               }
               outputs[i] = sigmoid(sum)
           }
           
           return outputs
       }
       
       func (nn *NeuralNetwork) Train(inputs []float32, targets []float32) {
           // Forward pass
           hidden := make([]float32, nn.HiddenSize)
           for i := 0; i < nn.HiddenSize; i++ {
               sum := nn.BiasHidden[i]
               for j := 0; j < nn.InputSize; j++ {
                   sum += inputs[j] * nn.WeightsIH[i][j]
               }
               hidden[i] = sigmoid(sum)
           }
           
           outputs := make([]float32, nn.OutputSize)
           for i := 0; i < nn.OutputSize; i++ {
               sum := nn.BiasOutput[i]
               for j := 0; j < nn.HiddenSize; j++ {
                   sum += hidden[j] * nn.WeightsHO[i][j]
               }
               outputs[i] = sigmoid(sum)
           }
           
           // Backward pass - Output layer
           outputErrors := make([]float32, nn.OutputSize)
           for i := 0; i < nn.OutputSize; i++ {
               outputErrors[i] = targets[i] - outputs[i]
           }
           
           outputDeltas := make([]float32, nn.OutputSize)
           for i := 0; i < nn.OutputSize; i++ {
               outputDeltas[i] = outputErrors[i] * sigmoidDerivative(outputs[i])
           }
           
           // Update weights and biases - Hidden to Output
           for i := 0; i < nn.OutputSize; i++ {
               for j := 0; j < nn.HiddenSize; j++ {
                   nn.WeightsHO[i][j] += nn.LearningRate * outputDeltas[i] * hidden[j]
               }
               nn.BiasOutput[i] += nn.LearningRate * outputDeltas[i]
           }
           
           // Hidden layer errors
           hiddenErrors := make([]float32, nn.HiddenSize)
           for i := 0; i < nn.HiddenSize; i++ {
               for j := 0; j < nn.OutputSize; j++ {
                   hiddenErrors[i] += outputDeltas[j] * nn.WeightsHO[j][i]
               }
           }
           
           hiddenDeltas := make([]float32, nn.HiddenSize)
           for i := 0; i < nn.HiddenSize; i++ {
               hiddenDeltas[i] = hiddenErrors[i] * sigmoidDerivative(hidden[i])
           }
           
           // Update weights and biases - Input to Hidden
           for i := 0; i < nn.HiddenSize; i++ {
               for j := 0; j < nn.InputSize; j++ {
                   nn.WeightsIH[i][j] += nn.LearningRate * hiddenDeltas[i] * inputs[j]
               }
               nn.BiasHidden[i] += nn.LearningRate * hiddenDeltas[i]
           }
       }
       
       // 遺伝的アルゴリズム
       type Individual struct {
           Genes   []float32
           Fitness float32
       }
       
       type GeneticAlgorithm struct {
           Population     []Individual
           PopulationSize int
           MutationRate   float32
           CrossoverRate  float32
           ChromosomeSize int
       }
       
       func NewGeneticAlgorithm(popSize, chromoSize int) *GeneticAlgorithm {
           ga := &GeneticAlgorithm{
               Population:     make([]Individual, popSize),
               PopulationSize: popSize,
               MutationRate:   0.01,
               CrossoverRate:  0.8,
               ChromosomeSize: chromoSize,
           }
           
           // Initialize random population
           for i := 0; i < popSize; i++ {
               genes := make([]float32, chromoSize)
               for j := 0; j < chromoSize; j++ {
                   genes[j] = float32(math.Random())*2 - 1 // -1 to 1
               }
               ga.Population[i] = Individual{Genes: genes, Fitness: 0}
           }
           
           return ga
       }
       
       func (ga *GeneticAlgorithm) EvaluateFitness(fitnessFunc func([]float32) float32) {
           for i := range ga.Population {
               ga.Population[i].Fitness = fitnessFunc(ga.Population[i].Genes)
           }
       }
       
       func (ga *GeneticAlgorithm) Selection() Individual {
           // Tournament selection
           best := ga.Population[0]
           for i := 1; i < 3; i++ { // Tournament size of 3
               idx := int(float32(len(ga.Population)) * float32(math.Random()))
               if ga.Population[idx].Fitness > best.Fitness {
                   best = ga.Population[idx]
               }
           }
           return best
       }
       
       func (ga *GeneticAlgorithm) Crossover(parent1, parent2 Individual) (Individual, Individual) {
           if float32(math.Random()) > ga.CrossoverRate {
               return parent1, parent2
           }
           
           crossoverPoint := int(float32(ga.ChromosomeSize) * float32(math.Random()))
           
           child1Genes := make([]float32, ga.ChromosomeSize)
           child2Genes := make([]float32, ga.ChromosomeSize)
           
           copy(child1Genes[:crossoverPoint], parent1.Genes[:crossoverPoint])
           copy(child1Genes[crossoverPoint:], parent2.Genes[crossoverPoint:])
           
           copy(child2Genes[:crossoverPoint], parent2.Genes[:crossoverPoint])
           copy(child2Genes[crossoverPoint:], parent1.Genes[crossoverPoint:])
           
           return Individual{Genes: child1Genes}, Individual{Genes: child2Genes}
       }
       
       func (ga *GeneticAlgorithm) Mutate(individual Individual) Individual {
           genes := make([]float32, len(individual.Genes))
           copy(genes, individual.Genes)
           
           for i := range genes {
               if float32(math.Random()) < ga.MutationRate {
                   genes[i] += (float32(math.Random())*2 - 1) * 0.1 // Small mutation
                   // Clamp to [-1, 1]
                   if genes[i] > 1 {
                       genes[i] = 1
                   } else if genes[i] < -1 {
                       genes[i] = -1
                   }
               }
           }
           
           return Individual{Genes: genes}
       }
    
  8. 画像処理とフィルタリング
       type Image struct {
           Width, Height int
           Pixels        [][]Color
       }
       
       func NewImage(width, height int) *Image {
           pixels := make([][]Color, height)
           for i := range pixels {
               pixels[i] = make([]Color, width)
           }
           return &Image{
               Width:  width,
               Height: height,
               Pixels: pixels,
           }
       }
       
       func (img *Image) SetPixel(x, y int, color Color) {
           if x >= 0 && x < img.Width && y >= 0 && y < img.Height {
               img.Pixels[y][x] = color
           }
       }
       
       func (img *Image) GetPixel(x, y int) Color {
           if x >= 0 && x < img.Width && y >= 0 && y < img.Height {
               return img.Pixels[y][x]
           }
           return Color{0, 0, 0, 0}
       }
       
       func (img *Image) ApplyGaussianBlur(radius float32) *Image {
           result := NewImage(img.Width, img.Height)
           
           // Gaussian kernel generation
           kernelSize := int(radius*3)*2 + 1
           kernel := make([][]float32, kernelSize)
           for i := range kernel {
               kernel[i] = make([]float32, kernelSize)
           }
           
           sum := float32(0)
           center := kernelSize / 2
           for y := 0; y < kernelSize; y++ {
               for x := 0; x < kernelSize; x++ {
                   dx := float32(x - center)
                   dy := float32(y - center)
                   distance := dx*dx + dy*dy
                   kernel[y][x] = float32(math.Exp(-float64(distance) / (2 * float64(radius*radius))))
                   sum += kernel[y][x]
               }
           }
           
           // Normalize kernel
           for y := 0; y < kernelSize; y++ {
               for x := 0; x < kernelSize; x++ {
                   kernel[y][x] /= sum
               }
           }
           
           // Apply convolution
           for y := 0; y < img.Height; y++ {
               for x := 0; x < img.Width; x++ {
                   var r, g, b, a float32
                   
                   for ky := 0; ky < kernelSize; ky++ {
                       for kx := 0; kx < kernelSize; kx++ {
                           px := x + kx - center
                           py := y + ky - center
                           
                           pixel := img.GetPixel(px, py)
                           weight := kernel[ky][kx]
                           
                           r += pixel.R * weight
                           g += pixel.G * weight
                           b += pixel.B * weight
                           a += pixel.A * weight
                       }
                   }
                   
                   result.SetPixel(x, y, Color{r, g, b, a})
               }
           }
           
           return result
       }
       
       func (img *Image) ApplySharpen() *Image {
           result := NewImage(img.Width, img.Height)
           
           // Sharpen kernel
           kernel := [][]float32{
               {0, -1, 0},
               {-1, 5, -1},
               {0, -1, 0},
           }
           
           for y := 1; y < img.Height-1; y++ {
               for x := 1; x < img.Width-1; x++ {
                   var r, g, b float32
                   
                   for ky := 0; ky < 3; ky++ {
                       for kx := 0; kx < 3; kx++ {
                           pixel := img.GetPixel(x+kx-1, y+ky-1)
                           weight := kernel[ky][kx]
                           
                           r += pixel.R * weight
                           g += pixel.G * weight
                           b += pixel.B * weight
                       }
                   }
                   
                   // Clamp values
                   if r > 1 { r = 1 } else if r < 0 { r = 0 }
                   if g > 1 { g = 1 } else if g < 0 { g = 0 }
                   if b > 1 { b = 1 } else if b < 0 { b = 0 }
                   
                   result.SetPixel(x, y, Color{r, g, b, img.GetPixel(x, y).A})
               }
           }
           
           return result
       }
       
       func (img *Image) AdjustBrightness(factor float32) *Image {
           result := NewImage(img.Width, img.Height)
           
           for y := 0; y < img.Height; y++ {
               for x := 0; x < img.Width; x++ {
                   pixel := img.GetPixel(x, y)
                   
                   r := pixel.R * factor
                   g := pixel.G * factor
                   b := pixel.B * factor
                   
                   // Clamp values
                   if r > 1 { r = 1 } else if r < 0 { r = 0 }
                   if g > 1 { g = 1 } else if g < 0 { g = 0 }
                   if b > 1 { b = 1 } else if b < 0 { b = 0 }
                   
                   result.SetPixel(x, y, Color{r, g, b, pixel.A})
               }
           }
           
           return result
       }
       
       func (img *Image) AdjustContrast(factor float32) *Image {
           result := NewImage(img.Width, img.Height)
           
           for y := 0; y < img.Height; y++ {
               for x := 0; x < img.Width; x++ {
                   pixel := img.GetPixel(x, y)
                   
                   // Contrast adjustment: (pixel - 0.5) * factor + 0.5
                   r := (pixel.R-0.5)*factor + 0.5
                   g := (pixel.G-0.5)*factor + 0.5
                   b := (pixel.B-0.5)*factor + 0.5
                   
                   // Clamp values
                   if r > 1 { r = 1 } else if r < 0 { r = 0 }
                   if g > 1 { g = 1 } else if g < 0 { g = 0 }
                   if b > 1 { b = 1 } else if b < 0 { b = 0 }
                   
                   result.SetPixel(x, y, Color{r, g, b, pixel.A})
               }
           }
           
           return result
       }
    

注意点

[編集]
  1. 精度の制限: float32は約7桁の有効数字しか持たないため、高精度が必要な計算では注意が必要です
       import "fmt"
       
       func demonstratePrecisionLoss() {
           // 精度の損失例
           var f float32 = 1234567.0
           f += 1.0
           fmt.Printf("1234567.0 + 1.0 = %f\n", f) // 1234568.000000(精度が失われる)
           
           // 小さな値の加算での問題
           var sum float32 = 0.0
           for i := 0; i < 1000000; i++ {
               sum += 0.0001
           }
           fmt.Printf("Expected: 100.0, Got: %f\n", sum) // 誤差が蓄積される
       }
       
       // 高精度が必要な場合の対策
       func highPrecisionSum(values []float32) float64 {
           var sum float64 = 0.0
           for _, v := range values {
               sum += float64(v)
           }
           return sum
       }
    
  2. 特殊値の処理: NaN、+Inf、-Infの適切な処理が必要です
       import "math"
       
       func checkSpecialValues(f float32) {
           if math.IsNaN(float64(f)) {
               fmt.Println("Value is NaN")
           } else if math.IsInf(float64(f), 1) {
               fmt.Println("Value is +Infinity")
           } else if math.IsInf(float64(f), -1) {
               fmt.Println("Value is -Infinity")
           } else {
               fmt.Printf("Value is normal: %f\n", f)
           }
       }
       
       func safeDiv(a, b float32) float32 {
           if b == 0 {
               if a > 0 {
                   return float32(math.Inf(1))
               } else if a < 0 {
                   return float32(math.Inf(-1))
               } else {
                   return float32(math.NaN())
               }
           }
           return a / b
       }
    
  3. 浮動小数点比較: 直接的な等価比較は避け、イプシロン比較を使用することが推奨されます
       const EPSILON float32 = 1e-6
       
       func floatEqual(a, b float32) bool {
           diff := a - b
           if diff < 0 {
               diff = -diff
           }
           return diff < EPSILON
       }
       
       func floatEqualRelative(a, b, epsilon float32) bool {
           if a == b {
               return true
           }
           
           diff := a - b
           if diff < 0 {
               diff = -diff
           }
           
           larger := a
           if b > larger {
               larger = b
           }
           if larger < 0 {
               larger = -larger
           }
           
           return diff <= epsilon*larger
       }
    
  4. パフォーマンス最適化: float64との使い分けとSIMD最適化の考慮
       import (
           "runtime"
           "time"
       )
       
       func benchmarkFloat32vs64() {
           size := 1000000
           data32 := make([]float32, size)
           data64 := make([]float64, size)
           
           // float32のベンチマーク
           start := time.Now()
           for i := 0; i < size; i++ {
               data32[i] = float32(i) * 1.5
           }
           elapsed32 := time.Since(start)
           
           // float64のベンチマーク
           start = time.Now()
           for i := 0; i < size; i++ {
               data64[i] = float64(i) * 1.5
           }
           elapsed64 := time.Since(start)
           
           fmt.Printf("float32: %v, float64: %v\n", elapsed32, elapsed64)
           fmt.Printf("Memory usage - float32: %d bytes, float64: %d bytes\n", 
               size*4, size*8)
       }
       
       // 並列処理での使用例
       func parallelProcess(data []float32, fn func(float32) float32) []float32 {
           result := make([]float32, len(data))
           numWorkers := runtime.NumCPU()
           chunkSize := len(data) / numWorkers
           
           var wg sync.WaitGroup
           for i := 0; i < numWorkers; i++ {
               wg.Add(1)
               go func(start, end int) {
                   defer wg.Done()
                   for j := start; j < end && j < len(data); j++ {
                       result[j] = fn(data[j])
                   }
               }(i*chunkSize, (i+1)*chunkSize)
           }
           wg.Wait()
           
           return result
       }
    
  5. JSON/XMLシリアライゼーション: 精度とパフォーマンスのバランス
       import (
           "encoding/json"
           "strconv"
       )
       
       type PreciseFloat32 struct {
           Value float32
       }
       
       // カスタムJSON marshaling(精度制御)
       func (pf PreciseFloat32) MarshalJSON() ([]byte, error) {
           // 有効数字7桁で制限
           str := strconv.FormatFloat(float64(pf.Value), 'g', 7, 32)
           return json.Marshal(str)
       }
       
       func (pf *PreciseFloat32) UnmarshalJSON(data []byte) error {
           var str string
           if err := json.Unmarshal(data, &str); err == nil {
               value, err := strconv.ParseFloat(str, 32)
               if err != nil {
                   return err
               }
               pf.Value = float32(value)
               return nil
           }
           
           return json.Unmarshal(data, &pf.Value)
       }
    
  6. 原子的操作: 並行アクセス時のatomic操作の実装(Go 1.19以降)
       import (
           "sync/atomic"
           "math"
       )
       
       type AtomicFloat32 struct {
           bits uint32
       }
       
       func NewAtomicFloat32(value float32) *AtomicFloat32 {
           return &AtomicFloat32{bits: math.Float32bits(value)}
       }
       
       func (af *AtomicFloat32) Load() float32 {
           return math.Float32frombits(atomic.LoadUint32(&af.bits))
       }
       
       func (af *AtomicFloat32) Store(value float32) {
           atomic.StoreUint32(&af.bits, math.Float32bits(value))
       }
       
       func (af *AtomicFloat32) Add(delta float32) float32 {
           for {
               old := atomic.LoadUint32(&af.bits)
               oldFloat := math.Float32frombits(old)
               newFloat := oldFloat + delta
               new := math.Float32bits(newFloat)
               if atomic.CompareAndSwapUint32(&af.bits, old, new) {
                   return newFloat
               }
           }
       }
       
       func (af *AtomicFloat32) CompareAndSwap(old, new float32) bool {
           return atomic.CompareAndSwapUint32(&af.bits, 
               math.Float32bits(old), math.Float32bits(new))
       }
    

float32型は、メモリ効率と計算速度を重視する場面、特にグラフィクス、ゲーム開発、リアルタイム処理、大規模な数値計算などで威力を発揮します。ただし、精度の制限、特殊値の処理、浮動小数点の比較など、適切な使用方法を理解して使用することが重要です。