Go/float32
表示
< 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 }
一般的なユースケース
[編集]- 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} }
- 物理シミュレーション
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 } }
- 色操作とグラフィクス
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} }
- 科学技術計算とデータ処理
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 }
- ゲーム開発
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, } }
- 音声処理とシンセサイザー
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 } } }
- 機械学習と数値最適化
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} }
- 画像処理とフィルタリング
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 }
注意点
[編集]- 精度の制限: 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 }
- 特殊値の処理: 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 }
- 浮動小数点比較: 直接的な等価比較は避け、イプシロン比較を使用することが推奨されます
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 }
- パフォーマンス最適化: 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 }
- 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) }
- 原子的操作: 並行アクセス時の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型は、メモリ効率と計算速度を重視する場面、特にグラフィクス、ゲーム開発、リアルタイム処理、大規模な数値計算などで威力を発揮します。ただし、精度の制限、特殊値の処理、浮動小数点の比較など、適切な使用方法を理解して使用することが重要です。